I want to test whether a file is a link to another link. I tried readlink but it doesn't work the way I need it:

ralph@bash4.4.12,1:~/subdir1 $ ll
lrwxrwxrwx 1 pi pi   13 Apr 10 14:34 hellolink -> subdir2/hello
lrwxrwxrwx 1 pi pi    9 Apr 10 14:34 hellolink2 -> hellolink
drwxr-xr-x 2 pi pi 4096 Apr 10 14:33 subdir2

Using readlink I now get either the canonicalized form of the ultimate target or the naked filename of the next link (hellolink):

ralph@bash4.4.12,1:~/subdir1 $ readlink -f hellolink2
ralph@bash4.4.12,1:~/subdir1 $ readlink hellolink2

But what I need is the full path to the file that hellolink2 points at:


Right now I'm doing something like this:

if [ -h "$(dirname hellolink2)/$(readlink hellolink2)" ] ; then 
            echo hellolink2 is a link

That looks like a lot of overhead when I do it many times in a loop, using find to feed it the filenames.

Is there an easier way?

  • 1
    Your test won't work in the case where the target of the symlink is an absolute path, and you probably can get rid of the extra dirname command subst by (conditionally) using some "${var%/*}" form. If you really want to make it more light-weight, you'll probably have to use another language, like C, perl, python, etc ;-) – mosvy Apr 10 '19 at 9:06
  • Thanks @mosvy, the construct if [ -h "${FILENAME%/*}"/"$(readlink "$FILENAME")" ] ; then ... does the job without the use of dirname. But the problem with readlink and the absolute path persists. Isn't there a command that does the job out of the box? Delivering the canonicalized form of the next linked file? It doesn't appear to be too much to ask. – Arjen Apr 10 '19 at 10:59

Use test -L (without readlink) to see if a file is a symbolic link.

if [ -L hellolink2 ]

Use realpath to get the absolute path of a symlink to a directory.

$ realpath hellolink2
| improve this answer | |
  • realpath for me gives the same result as readlink -f: ralph:~/subdir1 $ realpath hellolink2 /home/ralph/subdir1/subdir2/hello – Arjen Apr 10 '19 at 7:52

For what it's worth... following the suggestions in the comments above I rewrote the code that gets me the file that a link points to, even if that is another link, plus a few lines to test it:


function nextlinked ()
        if [ -h "$1" ]; then    # we have a link
                linked="$(readlink "$1")"
                [ "${linked:0:1}" == / ] && echo "$linked" || echo "${1%/*}"/"$linked"

add="   "

find / -print0 | while read -rd '' FILENAME ; do
        (( count++ ))
        if [ -h "$FILENAME" ] ; then # is this a link?
                printf "%6d " $count ; ls -ld "$filename" 2>&1
                filename="$(nextlinked "$filename" )"
                while [ "$filename" ] ; do
                        printf "%6d %s" $count "$header" ; ls -ld "$filename" 2>&1
                        filename="$(nextlinked "$filename")"

The question still stands: Is there an existing Linux command that does the job of the function nextlinked?

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.