4

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:

[email protected],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):

[email protected],1:~/subdir1 $ readlink -f hellolink2
/home/ralph/subdir1/subdir2/hello
[email protected],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?

Arjen
  • 188
  • 8
  • 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 ;-) –  Apr 10 '19 at 09: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

2 Answers2

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
Sjoerd
  • 431
  • 5
  • 10
  • realpath for me gives the same result as readlink -f: ralph:~/subdir1 $ realpath hellolink2 /home/ralph/subdir1/subdir2/hello – Arjen Apr 10 '19 at 07: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?

Arjen
  • 188
  • 8