File::Which, pwhich and App::pwhich
I recently took over maintenance of File::Which in order to fix some outstanding bugs. For those that are unawares, File::Which implements the unix capability of the which command as a portable Perl API. This allows you to search for commands in the system PATH, without actually needing to execute them. It takes the various idiosyncrasies of your platform into account so you don’t have to think about them. It also provides a command line interface called pwhich.
The main reason that I am bothering to write about this is as requested by multiple users in rt, I am splitting pwhich into its own distribution App-pwhich and this may have ramifications for those using pwhich. The reason that you’d want to do this is the vast majority of modules that use File::Which use it as an API and do not need pwhich at all. pwhich itself requires Test::Script for testing which pulls in further requirements. File::Which by itself has no non-core dependencies. I’ve already done a release that includes both File::Which and (the new) App::pwhich in one distribution. Early next week I plan on releasing both separately. File-Which will include a version of pwhich with a deprecation warning urging people who need it to install the App::pwhich version instead. At the end of April, unless there is an out cry I will remove pwhich from File-Which altogether, and you’ll need to install App-pwhich if you want pwhich.
Another “bug” was that Devel::CheckBin was not included in the SEE ALSO section of the File::Which, although including it in any SEE ALSO would have required a great deal of foresight, since File::Which preceded Devel::CheckBin by more than a decade. With hindsight I fixed that little bug. The main advantage, as I see it, to File::Which is that it contains documentation on how you might actually use it and how it works. It also doesn’t depend on ExtUtils::MakeMaker. For some systems that may not be a runtime package, or you might not want to pull in bits and pieces of MM just to find an executable. In terms of bugs, Devel::CheckBin will return false positives if the executable you are looking for is in the current directory on UNIX where the current directory should only be searched if it is explicitly included in the PATH.
The most serious bug is that File::Which did not deal correctly with fully qualified or relative paths. which(“/usr/bin/perl”) did not return anything, even though it was a valid command, and which /usr/bin/perl on the command line does work. It was suggested to check for the existence of commands using -f and -x. This is exactly what Devel::CheckBin does, but this is not quite correct, because as I mentioned before this may return false positives if the executable is in the current directory. Instead I opted to check using -f, -x and that the program being search for contained at least one slash (/) character. I stole this idea from the which implementation that comes with my Debian system.
I'm curious, I was told that IPC::Cmd::can_run was also useful as a portable "which" and it is core since 5.9.5; can I ask for an opinion between these?
File::Which can be called in list context:
Which may be useful for some applications, I've needed that capability at times in the past. Also the IPC::Cmd variant seems to also use ExtUtils::MakeMaker (as with Devel::CheckBin) for the heavy lifting, so it is fine if you don't mind pulling all of that in. And the semantics for executable in the current directory are different, and may not be what you expect if you are used to the traditional shell interface:
At least it prepends executables in the current directory with ./ so that they can be fed into system or qx
Reading comprehension is key. Reading the documentation I see you can get the list context version from IPC::Cmd too, but you need to set a global variable: