Stephane Chazelas wrote: > [ -e "$cmd" ] || cmd=$(command -v -- "$cmd") || exit > Bob Proulx wrote: > > Of course using command as you have done will work for bash. > > "command" is a POSIX command. So will work with every POSIX and > therefore every Unix conformant sh.
That is not strictly true. While 'command' is POSIX 'command -v' is actually an optional extension. A system only claiming POSIX conformance need not implement 'command -v'. See the online standards documents for more information. http://www.opengroup.org/onlinepubs/009695399/utilities/command.html And in fact the FreeBSD /bin/sh (among others) implements 'command' but not 'command -v'. So in practice it is not as portable as I would like it to be. Also the 'posh' shell (a specifically stripped down shell that aims to be a minimum posix shell) is useful to test for these types of non-posix'isms. It is specifically trying to be pedantic about only POSIX features. I am not suggesting that it is in wide use as a real programming shell. But it is useful for testing scripts. > Note that on some systems, the Unix conformant sh is not in /bin, > you may need to adapt the she-bang line I will never understand why Solaris has never updated /bin/sh and forces people to deal with /usr/xpg4/bin in userland. > (note that the she-bang line is a non-standard Unix feature). It is a standard Berkeley feature. And System V Release 4 adopted it. If you are trying to be portable to older systems I won't try to stop you. But I don't think that would be very widespread useful today. > > But I always feel better about using portable shell as much as > > possible. here is one way. > > > > pathfind() { > > OLDIFS="$IFS" > > IFS=: > > for p in $PATH; do > > if [ -x "$p/$*" ]; then > > IFS="$OLDIFS" > > echo "$p/$*" > > fi > > done > > IFS="$OLDIFS" > > } Note that I pulled most of that out of Debian's best practices document for maintainer scripts. Here is the original. http://www.debian.org/doc/developers-reference/ch-best-pkging-practices.en.html#s-bpp-debian-maint-scripts I modified it slightly for this case. You are right that I did introduce two bugs. The original only returned a status code. I used 'echo' (I know, I shouldn't have done that, echo is the most importable of commands) to print the path. And I made a separate goof because I did not refactor out the return properly in resetting the IFS. My bad. Thanks for pointing that out. However I think your other comments are incorrect. > On the contrary the code above has many problems: > > 1- If IFS was unset before, it becomes set to the empty string > after which has a different meaning. Your posted script did not unset IFS. Therefore that is not a concern there. I would not prefer 'command -v' over this because someone might unset IFS. There are lots of worse things that are possible. > 2- word splitting when IFS contains non-blank characters varies > from one shell to the next, and in most implementations > (including bash and AT&T ksh, it differs from the way the shell > splits $PATH internally to look up a command ("/bin:" is "/bin" > and "" as far as PATH look up is concerned Negative. In AT&T ksh (and others) "/bin:" is "/bin" and "." for PATH lookup. > while bash world splitting splits "/bin:" into only "/bin"). Negative. In bash "/bin:" is "/bin" and "." for PATH lookup. > 3- you forgot to disable filename generation, which means > wildcards will be expanded in "for p in $PATH" Negative. Wildcards will not be expanded there. > 4- there's a "break" (or return 0) missing, a "return 1" missing > if there's no match. In my example I did not care about the return code and so did not specify one. If you care about it then of course you will need to provide an exit code. However it was simply an example alternative to using the less-than-portable 'command -v' in your script. I was not doing your work for you. I expected you to do that yourself. > 5- echo is not a portable command, use printf instead as POSIX > suggests. On that I am guilty on all counts. I should have use an alternative command. If I really wanted to be portable I should have used the very functional but somewhat ugly here-document. cat <<EOF $p/$* EOF But I could not bring myself to do it. > > One thing to note about this script is that it canonicalizes path with > > respect to symlinks. You do say that but without much > > fanfare. > > That was intended. You can probably find as many caveats with > one approach or the other. Wow. You are not very forgiving of this in others but expect forgiveness yourself. That is not a very symetrical relationship. Bob _______________________________________________ Bug-bash mailing list Bug-bash@gnu.org http://lists.gnu.org/mailman/listinfo/bug-bash