5

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
/home/ralph/subdir1/subdir2/hello
ralph@bash4.4.12,1:~/subdir1 $ readlink hellolink2
hellolink

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

/home/ralph/subdir1/hellolink

Right now I'm doing something like this:

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

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 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 at 10:59
1

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
/home/ralph/subdir1/hellolink
  • realpath for me gives the same result as readlink -f: ralph:~/subdir1 $ realpath hellolink2 /home/ralph/subdir1/subdir2/hello – Arjen Apr 10 at 7:52
0

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:

#!/bin/bash

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

header=""
add="   "
count=0

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

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

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.