[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: PATH and $0
From: |
Stephane Chazelas |
Subject: |
Re: PATH and $0 |
Date: |
Wed, 2 Aug 2006 13:51:15 +0100 |
User-agent: |
mutt-ng/devel-r562 (Linux) |
On Thu, Jul 13, 2006 at 11:53:00PM -0600, Bob Proulx wrote:
> Stephane Chazelas wrote:
> > $0 will always contain the file path, unless the script was
> > started as:
> >
> > bash script.sh
> >
> > And there's no script.sh in the current directory (in which case
> > sh/bash will have looked up script.sh in $PATH).
>
> 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. Note that on some systems,
the Unix conformant sh is not in /bin, you may need to adapt the
she-bang line (note that the she-bang line is a non-standard Unix
feature).
> 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"
> }
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.
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 while bash world
splitting splits "/bin:" into only "/bin").
3- you forgot to disable filename generation, which means
wildcards will be expanded in "for p in $PATH"
4- there's a "break" (or return 0) missing, a "return 1" missing
if there's no match.
5- echo is not a portable command, use printf instead as POSIX
suggests.
>
> > #! /bin/sh -
> > dir=$(
> > cmd=$0
> > [ -e "$cmd" ] || cmd=$(command -v -- "$cmd") || exit
> > dir=$(dirname -- "$cmd")
> > cd -P -- "$dir" && pwd -P
> > ) || exit
> > # untested
> >
> > should give you the absolute path of the directory portion of
> > the script path (unless that directory ends in newline
> > characters).
>
> 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.
Note that if the binary file is a symlink itself, it doesn't
canonalise it.
[...]
> I think it is best to accept whatever path the user has provided
> verbatim. I would not try to canonicalize the path in any way. If
> the user has provided a path with /foo/bar/../../zoo/zam for example
> then I would just go with it because that path may actually be
> necessary just like that for some reason as yet unknown at this moment
> to us writing the code to be used in the future. The reason I think
> this way is that I have tried to do things like canonicalizing
> previously myself and gotten burned by it. I have learned it is
> better to avoid doing such things.
Then:
dir=$(
cmd=$0
[ -e "$cmd" ] || cmd=$(command -v -- "$cmd") || exit
dir=$(dirname -- "$cmd")
case $dir in
/*) ;;
*) dir=$(pwd -P)/$dir || exit;;
esac
printf '%s\n' "$dir"
) || exit
--
Stephane
- Re: PATH and $0,
Stephane Chazelas <=