views:

253

answers:

4

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.)

+1  A: 

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
bdijkstra
It doesn't seem to work on dangling links.
Dong Hoon
A: 

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...
Al
breaks on filenames containing "->"... thanks for the realpath tip though.
Dong Hoon
True... can't say I've ever had any files with -> in them. Readlink is definitely the way to go.
Al
A: 

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

ghostdog74
thx, but the awk-method breaks on filenames containing "->" as a substring; the find-method works, but a few conditions are lacking to restrict search to one file; i'd prefer the readlink command then.
Dong Hoon
+7  A: 

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
Torsten Marek
+1 Ooh, I didn't know about that one!
Al
Thanks! This is what I was looking for.
Dong Hoon
@Torsten The stat (readlink) utility appeared in NetBSD 1.6.
jleedev