Dong Hoon
Dong Hoon

Reputation: 889

How to compare 2 symbolic links in unix (Linux)?

What would be an elegant way of comparing 2 symbolic links in Unix?

Assume I have entered the following commands:

ln -s /usr/share/g s1
ln -s /usr/share/g s2
ln -s ../share/g /usr/lib/s3
ln -s /usr/share/h s4

then I would like to have a command that says that s1 and s2 are equal (whether /usr/share/g actually exists is not relevant), that s1 and s4 are not equal, s2 and s4 are not equal. (For my purpose it suffices that s3 is reported to differ from s1 and s2; however if comparison after path normalization could be done, that may be useful to.)

Upvotes: 3

Views: 3247

Answers (5)

Torsten Marek
Torsten Marek

Reputation: 86642

For GNU systems (and possibly others, but I can't say), there's readlink(1):

$ touch a
$ ln -s a b
$ readlink b
a

You can use that in comparisons:

$ test "$(readlink -f a)" = "$(readlink -f b)"
$ echo $?
0

Upvotes: 12

AlMa1r
AlMa1r

Reputation: 129

Wrong:

test $(readlink -f a) = $(readlink -f b)

because a or b may point to names with spaces, and in this case test will see more than 3 arguments.

Right:

cmp -s <(readlink -- a) <(readlink -- b)
echo $?

If you need to check recursively, say readlink -f instead of readlink. The double dashes -- inside the parens are needed only if a or b are variables, such as $1, $2, $var …. The switch -s is needed only if you need the result of the comparison for further processing rather than the printout of cmp. If you do wish to have a printout, better say

diff <(readlink -- a) <(readlink -- b)
echo $?

Upvotes: 0

DrAl
DrAl

Reputation: 72736

Either use stat -L or parse the output of ls -l (with sed or cut or similar):

fileone=`ls -l s1 | sed 's/.*-> //'`
filetwo=`ls -l s2 | sed 's/.*-> //'`
if [ "$fileone" = "$filetwo" ]
then
    echo "They're the same!"
fi

To normalise the path, use realpath:

fileone=`ls -1 s1 | sed 's/.*-> //'`
fileone=`realpath $fileone`
# etc...

Upvotes: 0

bdijkstra
bdijkstra

Reputation: 289

You could do a stat -L on the file and compare device and inode number. Quick example:

#!/bin/bash
DI_A=$(stat -c "%d.%i" -L "$1")
DI_B=$(stat -c "%d.%i" -L "$2")

if [ "$DI_A" == "$DI_B" ]; then
   echo "same file"
else
   echo "other file"
fi

Upvotes: 4

ghostdog74
ghostdog74

Reputation: 343137

2 ways i can think of, you can use ls -l on both files. you can see after the "->" of the output the actual path.eg

# ls -ltr msdfasdffff
lrwxrwxrwx 1 root root 10 Jun 30 19:05 msdfasdffff -> blah.sh

you can get the file name using

# ls -l msdfasdffff  | awk -F"-> " '{print $NF}'
blah.sh

then you can compare with another link.

the other way is use find

# var1=$(find . -name "s1" -printf "%l")
# var2=$(find . -name "s2" -printf "%l")

then you can compare the 2 variables using if/else

Upvotes: -1

Related Questions