6

Assume I have a file a which is a symlink to b, which in turn is a symlink to c.

With zsh's :A modifier, globbing a will result in an absolute path, resolving all symlinks, hence a(:A) will expand to the absolute path of c (on systems that have the realpath library).

Is it possible to get b (absolute or relative, but directly as a result of the globbing, not for example by looking at the output of ls -l) or even files up to arbitrary symlink depths?

A solution for Bash would also be interesting to know about.

1 Answer 1

7

You can always create a function to be used with the + glob qualifier:

$ zmodload zsh/stat
$ resolve() { [[ -L $REPLY ]] && stat -A REPLY +link -- ${1-$REPLY}; }
$ print -r - a(+resolve)
b
$ print -r - a(+resolve:a)
/home/stephane/b (though see caveat below)

Note that if you do a(+resolve+resolve), the second resolve will still be called on the original filename (a), not on the result of the first resolve (b). You could however do:

$ print -r - a(e['resolve && resolve'])
c

to chain the two resolves. However (and the caveat also applies to the usage of :a above), although it will work for this particular example, that's not a valid thing to do in the general case, as targets of symlinks, when relative paths, are relative to the parent of the symlink, not the current working directory, so if dir/link points to foo, that's the dir/foo file, not foo, so it's only valid when resolving symlinks in the current working directory.

That would stop being a problem though if we change our resolve so it computes a full path of the target of the symlink:

resolve() {
  local target
  [[ -L $REPLY ]] &&
    stat -A target +link -- ${1-$REPLY} &&
    case $target in
      (/*) REPLY=$target;;
      (*) REPLY=${REPLY:h:a}/$target;;
    esac
}

bash has no glob qualifier, nor any interface to readlink() (like zsh's stat builtin), but on some systems, you'll find a readlink command:

$ readlink a
b
1
  • Excellent answer, thanks! Aug 16, 2021 at 7:02

You must log in to answer this question.

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