Suppose file stores the pathname of a non-dir file.

How can I get its parent directory?

why does the following way by appending /.. to its value not work

$ cd $file/..   
cd: ./Tools/build.bat/..: No such file or directory


  • Example of such a pathname?
    – schaiba
    Mar 16, 2017 at 16:27
  • dirname may be what you want
    – ivanivan
    Mar 16, 2017 at 16:27
  • @schaiba ./Tools/build.bat as in the example
    – Tim
    Mar 16, 2017 at 16:28
  • 2
    Do you ever search before asking or ask basic questions just for the upvotes? It's hard to believe you couldn't find this doing a little searching. Mar 17, 2017 at 13:22

5 Answers 5



$ file=./Tools/build.bat

With a POSIX compatible shell (including zsh):

$ echo "${file%/*}"

With dirname:

$ echo "$(dirname -- "$file")"

(at least GNU dirname takes options, so the -- is required in case the path starts with a dash.)

  • Thanks. why does the following way by appending /.. to its value not work
    – Tim
    Mar 16, 2017 at 17:35
  • 2
    okay, I see it is because $file isn't a directory
    – Tim
    Mar 16, 2017 at 17:41
  • 2
    Do you really need the echo?
    – gardenhead
    Mar 16, 2017 at 21:03
  • Just a note: I use dirname all the time, as I find it more expressive.
    – Pysis
    Mar 16, 2017 at 21:07
  • 1
    @gardenhead, only for demonstration. Of course really we'd just do somecommand "${file%/*}" (And even for printing, printf would arguably be better.)
    – ilkkachu
    Mar 16, 2017 at 21:08

If you are using zsh try :h modifier

cd $file:h

You can add n of them to go n levels up in directory structure.

  • 1
    Also works in csh/tcsh where it comes from though in those shells, you'll need to add a :q to account for directory names that contain blanks or wildcards. Mar 16, 2017 at 17:27

this is quite simple with the command dirname, just do the folowing:

cd "$(dirname -- "$file")"

now you can even go further on this

cd "$(dirname -- "$file")"
cd "$(dirname -- "$file")"/..

first cd will get you to /home/switch87, the seccond to /home


get the directory of the file in a very general way (when file is known with a relative or absolute pathname, or no path at all):

the_dir="$(cd -P -- "$(dirname -- "${filename}")" && pwd)"

So to get the parent of that directory:

the_parent_dir="$(cd -P -- "$(dirname -- "${filename}")/.." && pwd)"

cd -P : print the "real" (physical) path, instead of a path using symbolic links. If you take the -P out it also works, but you may get a different result ( for exemple: cd / ; ln -s /long/path/here shortcut ; cd shortcut ; pwd will show you the path: /shortcut, whereas if you added -P to cd you would see /long/path/here instead)


I prefer to use a combination of readlink and dirname.

parent=$(readlink -f "$(dirname "$file")")
cd $parent

dirname cuts the filename from the path and readlink -f turns $path/.. into a canonical path.

  • That potentially gives a different path to the directory, which may not be desirable. Mar 16, 2017 at 23:55

Not the answer you're looking for? Browse other questions tagged .