13

I've got a script to recursively create symlinks in my home directory to my settings directory, to keep the files under version control. I would like it to skip files which are already symlinked via a parent directory. That is, if I have these files/directories:

~/foo/ -> ~/settings/foo/
~/settings/foo/
~/settings/foo/bar

, how do I check that ~/foo/bar and ~/settings/foo/bar are the same file?

Edit: D'oh, another few minutes of searching revealed the answer: readlink -f $path

10

If two files have the same deviceID and inode, they're the same file. The stat command line tool makes this easy to find and this solution is POSIX shell-compliant.

if [ "$(stat -L -c %d:%i FILE1)" = "$(stat -L -c %d:%i FILE2)" ]; then
  echo "FILE1 and FILE2 refer to a single file, with one inode, on one device."
else
  echo "no match"
fi

The -L flag in each stat means this works for both symlinked and hardlinked files.

2
  • 6
    To follow symbolic links, you need stat -L. Oct 6 '10 at 20:13
  • Like @Gilles said, without the -L switch, you may get wrong results on some distributions
    – Olaseni
    Nov 23 '17 at 4:54
21

Many shells have a -ef operator for the test builtin (or its synonym [) to test whether two paths point to the same existing file (following symbolic links). This includes bash, dash, pdksh, ksh88, ksh93 and zsh, but not POSIX sh. In bash, ksh or zsh, you can also use -ef in the [[ … ]] conditional construct.

if ! [ "$1" -ef "$2" ]; then # $1 and $2 are different files
3
  • 2
    According to my manpage, -ef does exactly the same thing as Rich Homolka's answer.
    – user13852
    May 10 '13 at 14:51
  • 2
    @user13852 -ef has the advantage of being more portable (also slightly faster, but not so that you'd notice most of the time). For example it works on *BSD, OSX, BusyBox as well as Linux/Cygwin (GNU). It's also clearer, as it does exactly what is required. The only advantage I can see to calling stat is when you don't want to follow symlinks. May 10 '13 at 14:59
  • @user13852 And -ef follows symlinks, unlike Rich Homolka's original answer. stat -L is needed for that. (In most cases, following symlinks is more appropriate.) Feb 15 '21 at 16:36
0

For softlinks (created with ln -s) you can use realpath. This won't work for hardlinks though.

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.