Beware that $0
can be a relative path, so calling cd
twice might not work. Apart from that, extracting the directory part of $0
works in most cases. Most is not the same as all. Some cases where it can fail include:
- The script is not invoked by running its path but by calling a shell on it, e.g.
bash myscript
(which does a PATH
lookup).
- The script is moved during its execution.
As long as you document that your script must be called without shenanigans, taking the directory part of $0
is ok.
You need to be a little careful; it's possible for $0
to not contain a slash at all, if it was found via an empty PATH
entry or, with some shells, a PATH
entry for .
. This case is worth supporting, and it means you need to take precautions with ${0%/*}
.
The dirname
approach isn't completely straightforward either. The command substitution eats up newlines at the end. And with both approaches you need to take care that the string could begin with -
and be interpreted as an option; pass --
to terminate a command's option list.
case "$0" in
*/*) cd -- "${0%/*}";;
*) cd -- "$0";;
esac
or
cd -- "$(dirname -- "$0"; echo /)"
Regarding the double quotes, you're asking the wrong question. "$0"
is the value of the parameter 0
. $0
, unquoted, is the value of the parameter 0
split at characters in IFS
with each element then interpreted as a glob pattern and replaced by matching files if there are any (that latter part only if globbing is not turned off). You don't mean the value of the parameter 0
split at characters in IFS
with each element then interpreted as a glob pattern and replaced by matching files if there are any (that latter part only if globbing is not turned off), do you? You mean the value of the parameter 0
. So write what you mean: "$0"
.
The only reason your tests didn't choke is that you didn't try it with problematic names and you tested with a specific shell that happens to repair your mistake in this specific scenario. With a directory name like foo bar
, you end up passing two arguments foo
and bar
to the cd
command; bash's cd
command interprets this as “change to the directory obtained by concatenating foo
, a space and bar
” so it happens to build back the right name. A different shell might interpret this as “complain about a spurious argument”, “change to the directory foo
”, or “change to the directory obtained by replacing foo
by bar
in the current working directory”. With bash, your script would fail if the name contained two consecutive spaces, for example.
dirname $0
is.
since you called the script as./ch.sh
. If you had called it with its full pathname then you would see that quotes are required because thendirname
would produce a path that has a space in it. – Celada Mar 07 '16 at 20:03