-1

I create a hard link to student.sh and a soft link to student.sh. The hard links have different inodes than soft links. But when comparing the soft with student.sh by using the test -ef command, it does not work as expected. I had checked the manuals of the ln and test commands but still confused with them.

$ man test
$ man ln

FILE1 -ef FILE2
  FILE1 and FILE2 have the same device and inode numbers

enter image description here

$ ln /home/pi/Desktop/links/student.sh hard
$ ln -s /home/pi/Desktop/links/student.sh soft

$ ls -ial
278224 drwxr-xr-x  2 pi pi 4096  6月  5 23:31 .
262125 drwxr-xr-x 12 pi pi 4096  6月  5 23:17 ..
278227 -rwxr-xr-x  2 pi pi   43  6月  5 23:20 hard
278225 lrwxrwxrwx  1 pi pi   33  6月  5 23:31 soft -> /home/pi/Desktop/links/student.sh
278227 -rwxr-xr-x  2 pi pi   43  6月  5 23:20 student.sh

test

# ❌ inode is different
$ [ ./student.sh -ef ./soft ] && echo yes || echo no
yes

$ [ ./student.sh -ef ./hard ] && echo yes || echo no
yes

update test case

./test.sh

#!/usr/bin/env bash

if [[ ./student.sh -ef ./soft ]]; then
  echo "yes"
else
  echo "no"
fi

if [[ ./student.sh -ef ./hard ]]; then
  echo "yes"
else
  echo "no"
fi
$ ./test.sh 
yes
yes

wanted

# inode is different, so it should output no ✅
$ [ ./student.sh -ef ./soft ] && echo yes || echo no
no

$ [ ./student.sh -ef ./hard ] && echo yes || echo no
yes

enter image description here

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
  • 2
    Because it follows links and compares the targets. – Barmar Jun 05 '23 at 16:34
  • This allows you to do `if [ $link1 -ef $link2 ]` to test if they both refer to the same file. – Barmar Jun 05 '23 at 16:37
  • 1
    BTW, note that `a && b || c` is **not** the same as `if a; then b; else c; fi`. Use the latter unless you're very sure -- see [one-liner if/else not working as intended](https://stackoverflow.com/questions/76371824/one-liner-if-else-not-working-as-intended) and/or [BashPitfalls #22](http://mywiki.wooledge.org/BashPitfalls#cmd1_.26.26_cmd2_.7C.7C_cmd3). – Charles Duffy Jun 05 '23 at 17:07
  • @CharlesDuffy You're right, but in my case I just wanted to make testing easier. – xgqfrms Jun 06 '23 at 06:07
  • **DO NOT post images of code, data, error messages, etc.** - copy or type the text into the question. [ask] – Rob Jun 06 '23 at 06:57
  • I'm voting to close this question because it's no longer needed – xgqfrms Aug 28 '23 at 06:48

1 Answers1

1

Like Barmar mentioned in a comment, and as documented in the bash manual section on conditional expressions:

Unless otherwise specified, primaries that operate on files follow symbolic links and operate on the target of the link, rather than the link itself.

You can use stat(1) to get the device number and inode without following symbolic links, and compare those values, though:

$ is_same_file () { test "$(stat -c "%d %i" "$1")" = "$(stat -c "%d %i" "$2")"; }
$ if is_same_file student.sh hard; then echo yes; else echo no; fi
yes
$ if is_same_file student.sh soft; then echo yes; else echo no; fi
no

This should work on any POSIXish shell, not just bash, as long as the GNU coreutils stat(1) command is available, which seems a safe bet since you're talking about Linux. Might need to be adjusted if using some other enviroment; the NetBSD stat(1), for example, uses -f instead of -c).

Shawn
  • 47,241
  • 3
  • 26
  • 60