shell 如何在Bash中检查两个路径是否相等?

sycxhyv7  于 12个月前  发布在  Shell
关注(0)|答案(5)|浏览(151)

在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方法可以做到这一点?

zfycwa2u

zfycwa2u1#

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

fjnneemd2#

可以使用realpath。举例来说:

realpath ~/file.txt
Result: /home/testing/file.txt

realpath ./file.txt
Result: /home/testing/file.txt

再看看类似的答案:bash/fish command to print absolute path to a file

bvn4nwqk

bvn4nwqk3#

原生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
2lpgd968

2lpgd9684#

如果您安装了coreutils 8.15或更高版本,则可以使用realpath命令完全规范化路径。它删除所有...组件,使路径成为绝对路径,并解析所有符号链接。由此可见:

if [ "$(realpath "$path1")" = "$(realpath "$path2")" ]; then
   echo "Same!"
fi
u5rb5r59

u5rb5r595#

当涉及其他因素时,基于解析符号链接的方法会失败。例如,绑定挂载。(如mount --bind /raid0/var-cache /var/cache
使用find -samefile是一个很好的选择。这将比较文件系统和inode号。
-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

显然,这适用于指向目录或任何类型的文件的路径,而不仅仅是普通文件。它们都有inode编号。
使用方法:

$ 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和路径列表的符号链接引用。因此,其中一个或两个都可以是符号链接。

相关问题