bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: PATH and $0


From: Bob Proulx
Subject: Re: PATH and $0
Date: Sat, 12 Aug 2006 01:51:12 -0600
User-agent: Mutt/1.5.9i

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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]