Linux shell命令test -ef在符号链接上不按其手册描述的方式工作的原因是什么?

huangapple go评论66阅读模式
英文:

Why does the Linux shell command test -ef not work on soft links as its manual describes?

问题

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
$ 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

Linux shell命令test -ef在符号链接上不按其手册描述的方式工作的原因是什么?

英文:

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

Linux shell命令test -ef在符号链接上不按其手册描述的方式工作的原因是什么?

$ 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

Linux shell命令test -ef在符号链接上不按其手册描述的方式工作的原因是什么?

答案1

得分: 1

Barmar在评论中提到,并且在关于条件表达式的bash手册章节中有记录:

除非另有指定,操作文件的主体会跟随符号链接并操作链接的目标,而不是链接本身。

您可以使用stat(1)来获取设备号和inode,而不跟随符号链接,然后比较这些值,如下所示:

$ 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

这应该适用于任何POSIX兼容的Shell,不仅仅是bash,只要GNU coreutils的stat(1)命令可用,考虑到您正在谈论Linux,这似乎是一个安全的选择。如果使用其他环境,可能需要进行调整;例如,NetBSD的stat(1)使用-f而不是-c

英文:

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

huangapple
  • 本文由 发表于 2023年6月6日 00:29:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76408365.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定