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

Before I write a script, anyone know an easy way to do the following:

$ pwd
$ ls -l
lrwxr-xr-x  1 username  admin  48 Apr 17  2012 foo.sh -> /bar/foo.sh
$ cd /bar
$ ls

i.e., in the directory /foo/bar, I'd like to do something like cdl (cd link), which would take me to the directory of the linked file (or alternatively to the linked directory, if that happened to be the case—if it was I could type cd -P /bar).

share|improve this question
May I ask what your motivation is for doing this? Also, do you want to resolve symlinks recursively? (If /bar is itself a symlink, would you want to follow it?) – 200_success Jun 16 '13 at 8:23
up vote 6 down vote accepted

In zsh, there's a modifier for that, or rather two: A to resolve symbolic links (with realpath) and h to extract the “head” (i.e. the dirname).

cd $file(:A:h)

This only works if the symbolic isn't broken. If there is a chain of symbolic links, it is followed until the ultimate target. If the directory was reached through a symbolic link, you'll be in its target (as with cd -P).

Without zsh, if you have the readlink utility, and you want to change to the directory containing the target of the symbolic link:

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

The target of the link could be itself a symlink. If you want to change to the directory containing the ultimate target of the link, you can call readlink in a loop:

while [ -L "$file" ]; do
  target=$(readlink -- "$file")
  while case $target in */) target=${target%/};; *) false;; esac; done
  case $target in
    */*) cd -- "${target%/*}"; target=${target#**/};;

On Linux, assuming the symlink isn't broken, you can use readlink -f to canonicalize the path:

t=$(readlink -f -- "$file")
cd "${t%/*}"
share|improve this answer
Excellent answer: cd $file(:A:h) is exactly what I was looking for! – Chauncey Garrett Jun 18 '13 at 4:20

You can use readlink to resolve the symbolic link and then dirname to get its directory.

cdl () {
    cd "$(dirname "$(readlink "$1")")"; 
bash-3.2$ pwd
bash-3.2$ ls -l
total 8
lrwxr-xr-x  1 root  wheel  11 Jun 15 19:10 foo.sh -> /bar/foo.sh
bash-3.2$ cdl foo.sh 
bash-3.2$ pwd 
share|improve this answer
N.B. this is a perfect example of why to use $() instead of backticks. – Kevin Jun 15 '13 at 23:13

one line:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
share|improve this answer
This is your second one-line answer (it even appears to be exactly the same answer). Again, one-line answers are not the most helpful. Please expand your answers to include more helpful information and explanation (including supporting links and documentation). – HalosGhost Aug 29 '14 at 3:04

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.