Check if two paths are pointing to the same file

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


Solution 1:

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.

Solution 2:

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