Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

The $0 variable contains the path info of the script.

  • How can I change the path info to absolute path? I mean how to process ~, ., .. or similar?
  • How can I split the path info into directory and file name?

I could use python/perl for this, but I want to use bash if possible.

share|improve this question
what are you trying to achieve? btw. calling a script with ~/foo.sh will expand ~ into my home directory for $0 with my bash version (GNU bash, version 4.1.5(2)-release-(x86_64-unknown-linux-gnu)) – echox Sep 7 '10 at 21:19
up vote 18 down vote accepted

You don't need to process things like ~, the shell does it for you. That's why you can pass ~/filename to any script or program and it works -- all those programs don't handle ~ themselves, your shell converts the argument to /home/username/filename and passes that to the program instead:

$ echo ~/filename

If you need a canonical filename (one that doesn't include things like ..), use realpath (thanks Neil):

$ realpath ~/../filename

As for splitting the path into directory name and filename, use dirname and basename:

$ dirname /foo/bar/baz

$ basename /foo/bar/baz
share|improve this answer
I think you mean realpath, not readlink. readlink won't work in the common situation, ie when the link uses a relative path and you are not in the same dir as the link. – Neil Mayhew Sep 10 '10 at 23:03
@Neil realpath is better, but readlink seems to work when I try it; do you know of an example where it fails? – Michael Mrozek Sep 11 '10 at 8:44
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. This returns foo and realpath returns /tmp/foo, which is what you want. – Neil Mayhew Sep 11 '10 at 23:47
@Neil Ah, so it does. Fixed, thanks – Michael Mrozek Sep 12 '10 at 0:14
@Neil, @Michael: readlink -f (note -f) is almost equivalent to realpath, and it's more portable: readlink -f in GNU coreutils and exists on a few other systems as well; realpath is packaged separately and may not be installed (e.g. only 5 not-that-common packages depend on it in Ubuntu 10.04 or Debian lenny). – Gilles Nov 13 '10 at 11:33

Using dirname and basename like mentioned by Michael should be the safest way to get what you want.

Anyway if you really want to do this with "bash only tools" you could use parameter substitution:

echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo "${filename##*.}"      # data
                            # Extension of filename.

This example is directly taken from the Advanced Bash Scripting Guide which is worth a look.

The explanation is pretty simple:

${var#Pattern} Remove from $var the shortest part of $Pattern that matches the front end of $var. ${var##Pattern} Remove from $var the longest part of $Pattern that matches the front end of $var.

Look at the pattern like some regex and the # or ## as some kind of greedy/non-greedy modifier.

This might become useful if you will have to do some more complicated extractions of a paths part.

share|improve this answer
Beware when using ${...##...} and friends rather than dirname and basename that they don't work in all cases. For example both ${0##*/} and ${0%/*} expand to the same as $0 if $0 doesn't contain a /. – Gilles Sep 7 '10 at 22:11
@Gilles I understand why ${0%/*} is not a good alternative to dirname. However, what's wrong with using ${0##*/} instead of basename? – toxalot Mar 16 '14 at 9:24
@toxalot For this one, the only problem is when $0 is a directory name with a trailing /. But I regret my advice, because dirname doesn't do any better. – Gilles Mar 16 '14 at 14:18

realpath is a command which tells you the real path (removes .. and symbolic links etc.)

It is standard with FreeBSD. According to this discussion it's also available for Linux:


That discussion also offers a bash solution:

$ bash -c "cd /foo/../bar/ ; pwd"
share|improve this answer
Exactly, something like this usually works: MYDIR="$(cd $(dirname "$0"); pwd)" – Kevin Cantu Sep 8 '10 at 22:33

Your Answer


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.