Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

In a script I get in $0 the possible relative path to it. For converting it to absolute I've found this solution which I don't understand:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

My problem is the magic inside of ${0%/*} and ${0##*/}. It looks like the former extracts the dirname and the latter extracts the filename, I just don't get how.

share|improve this question
2  
That uses parameter expansion, but it didn't work for me. If your script is only going to be used on Linux, you can use readlink -f $0 to get the canonical path. –  Shawn J. Goff Mar 18 '11 at 13:22
1  
@Shawn: 1 great comment vote because you introduced the right thinking: "That uses parameter expansion, but it didn't work for me". The dirname util is useful here. –  D4RIO Mar 18 '11 at 14:09
    
mywiki.wooledge.org/BashFAQ/028 and cyberciti.biz/faq/… says BASH_SOURCE is better than $0, as $0 gives the user's typed in command, which might not be the currently executing script. –  Joel Purra Jun 26 at 11:06

5 Answers 5

up vote 5 down vote accepted

Definitions:

${string%substring} deletes shortest match of $substring from the end of $string.

${string##substring} deletes longest match of $substring from the start of $string.

Your example:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} deletes everything after the last slash, giving you the directory name of the script (which might be a relative path).

${0##*/} deletes everything upto the last slash, giving you just the name of the script.

So, this command changes to the directory of the script and concatenates the current working directory (given by $PWD) and the name of the script giving you the absolute path.

To see what is going on try:

echo ${0%/*}
echo ${0##*/}
share|improve this answer
    
Add double quotes around all variable expansions to cope with (almost all) file names containing shell special characters. –  Gilles Mar 18 '11 at 20:42

Shawn had the simplest solution: readlink -f $0. If you want to be absolutely sure to handle weird file names, you can use this:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Documentation

share|improve this answer
    
Good to see final newlines correctly handled. Unfortunately readlink -fn is specific to Linux, NetBSD and OpenBSD. –  Gilles Mar 18 '11 at 20:41

If you want to learn Shell Parameter Expansion, you can read it from here, but Expansion isn't always a good choice. In this case, almost every Unix like system has 2 good utils:

basename
dirname

The first will extract the filename, while the second will extract the path, so, if you have $0, say:

dirname $0

And you'ill get the path.

Cheers

share|improve this answer
    
dirname can return relative paths –  opticyclic Apr 18 '13 at 21:02

Here is a safer and more readable way to do this job:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Notes:

  • If $0 is a bare filename with no preceding path, the original script will fail but the one given here will work. (Not a problem with $0 but could be in other applications.)
  • Either approach will fail if the path to the file doesn't actually exist. (Not a problem with $0, but could be in other applications.)
  • The unset is essential if your user may have CDPATH set.
  • Unlike readlink -f or realpath, this will work on non-Linux versions of Unix (e.g., Mac OS X).
share|improve this answer

Introducing pwd, the bash builtin. Also found in the GNU coreutils package.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.