在 Bash 中检查两条路径是否相等的最佳方法是什么?例如,给定目录结构
~/
Desktop/
Downloads/ (symlink to ~/Downloads)
Downloads/
photo.png
并假设当前目录是主目录,以下所有内容都是等效的:
./ and ~
~/Desktop and /home/you/Desktop
./Downloads and ~/Desktop/Downloads
./Downloads/photo.png and ~/Downloads/photo.png
是否有原生的 Bash 方法可以做到这一点?
Bash 的
test
命令有一个 -ef
运算符用于此目的:
if [ ./ -ef ~ ]; then ...
if [ ~/Desktop -ef /home/you/Desktop ]; then ...
这里是该操作员的文档:
$ help test | grep -e -ef
FILE1 -ef FILE2 True if file1 is a hard link to file2.
请注意,操作符的两个路径都必须引用现有文件或目录才能正常工作。如果文件或目录不存在,测试将返回 false。
如果您愿意,在这种情况下可以使用双括号而不是单括号:
if [[ ./ -ef ~ ]]; then ...
您可以使用
realpath
。例如:
realpath ~/file.txt
Result: /home/testing/file.txt
realpath ./file.txt
Result: /home/testing/file.txt
另请看一下这里的类似答案:bash/fish 命令打印文件的绝对路径
原生 bash 方式:
pwd -P
返回物理目录,无论符号链接如何。
cd "$dir1"
real1=$(pwd -P)
cd "$dir2"
real2=$(pwd -P)
# compare real1 with real2
另一种方法是使用
cd -P
,它将跟随符号链接,但将您留在物理目录中:
cd -P "$dir1"
real1=$(pwd)
cd -P "$dir2"
real2=$(pwd)
# compare real1 with real2
如果您安装了 coreutils 8.15 或更高版本,则可以使用
realpath
命令来完全规范化路径。它删除所有 .
和 ..
组件,使路径成为绝对路径,并解析所有符号链接。因此:
if [ "$(realpath "$path1")" = "$(realpath "$path2")" ]; then
echo "Same!"
fi
当涉及其他因素时,基于解析符号链接的方法会失败。例如,绑定安装。 (就像
mount --bind /raid0/var-cache /var/cache
使用
find -samefile
是一个不错的选择。这将比较文件系统和索引节点号。
-samefile
是 GNU 扩展。即使在 Linux 上,busybox find 也可能没有它。 GNU 用户空间和 Linux 内核经常结合在一起,但你可以只使用其中一个,而这个问题仅标记为 Linux 和 bash。)
# params: two paths. returns true if they both refer to the same file
samepath() {
# test if find prints anything
[[ -s "$(find -L "$1" -samefile "$2")" ]] # as the last command inside the {}, its exit status is the function return value
}
例如在我的系统上:
$ find /var/tmp/EXP/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb -samefile /var/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb
/var/tmp/EXP/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb
$ stat {/var/tmp/EXP,/var}/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb
File: ‘/var/tmp/EXP/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb’
...
Device: 97ch/2428d Inode: 2147747863 Links: 1
...
File: ‘/var/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb’
Device: 97ch/2428d Inode: 2147747863 Links: 1
如果您想在最终路径组件中跟踪符号链接,则可以使用
find -L
:
$ ln -s /var/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb foo
$ find /var/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb -samefile foo
$ find -L /var/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb -samefile foo
/var/cache/apt/archives/bash_4.3-14ubuntu1_amd64.deb
显然,这适用于引用目录或任何类型文件的路径,而不仅仅是常规文件。它们都有索引节点号。
用途:
$ samepath /var/cache/apt/ /var/tmp/EXP/cache/apt/ && echo true
true
$ ln -sf /var/cache/apt foobar
$ samepath foobar /var/tmp/EXP/cache/apt/ && echo true
true
samepath /var/tmp/EXP/cache/apt/ foobar && echo true
true
samepath foobar && echo true # doesn't return true when find has an error, since the find output is empty.
find: `': No such file or directory
因此
find -L
取消引用 -samefile
以及路径列表的符号链接。所以其中一个或两个都可以是符号链接。