cd to directory of a symbolically linked file

6,185

Solution 1

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#**/};;
  esac
done

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

t=$(readlink -f -- "$file")
cd "${t%/*}"

Solution 2

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
/foo/bar
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 
/bar
bash-3.2$ 
Share:
6,185

Related videos on Youtube

Chauncey Garrett
Author by

Chauncey Garrett

Updated on September 18, 2022

Comments

  • Chauncey Garrett
    Chauncey Garrett almost 2 years

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

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

    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).

    • 200_success
      200_success about 11 years
      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?)
  • Kevin
    Kevin about 11 years
    N.B. this is a perfect example of why to use $() instead of backticks.
  • Chauncey Garrett
    Chauncey Garrett about 11 years
    Excellent answer: cd $file(:A:h) is exactly what I was looking for!
  • Jakob Bennemann
    Jakob Bennemann almost 10 years
    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).