如何判断两个目录是否指向同一个位置

如何判断两个目录是否指向同一个位置

以下路径是否指向同一磁盘位置?

/home/username
/app/home/username

答案1

依次更改目录到每个目录并查看pwd -P.使用该-P标志,pwd将显示物理当前工作目录以及已解析的所有符号链接。

答案2

有两种基本方法可以检查两个文件是否相同。第一个是检查它们的路径是否相同。这没有误报,但有大量误报。一个明显的漏报情况是涉及符号链接。您可以通过解析符号链接来处理这种情况。对于您有权更改的现有目录,可以使用pwd -P.

absolute_path1="$(cd -- "$path1" && pwd -P; echo .)" &&
absolute_path2="$(cd -- "$path2" && pwd -P; echo .)" &&
[ "$absolute_path1" = "$absolute_path2" ]

额外的内容echo .处理了一种罕见的情况,即其中一个目标的文件名以换行符结尾:如果换行符是命令替换的最后一个字符,它将被删除,因此片段将错误地报告foo␤foo

仍然存在潜在的漏报。对于目录,硬链接不是问题,因为大多数操作系统和文件系统都禁止硬链接目录。可能发生的情况是,同一目录以某种方式在不同位置可用,例如:

  • 在两个不同的位置安装相同的远程文件系统,例如

    mount server:/some/where /mnt1
    mount server:/some/where /mnt2
    compare /mnt1 /mnt2
    
  • A绑定挂载

  • 任何可堆叠文件系统,即以不同方式呈现文件系统的方式,您认为目录的视图与原始目录相比没有足够的变化,实际上是相同的目录。例如,可堆栈文件系统会转换文件名,并且目录名称在转换下保持不变。

在这些示例中,目录是否真的相同是有争议的。这显示了“同一文件”概念在边缘情况下的局限性。

第二种基本方法是检查内核提供的标识:设备和inode。这stat系统调用报告每个文件的两个属性:

  • 设备号 ( st_dev),传统上是包含文件所在文件系统的块设备(磁盘分区)的标识;
  • inode 编号 ( st_ino),传统上是标识同一文件系统中的文件的唯一编号。

通常,当且仅当两个文件具有相同的设备和索引节点号时,它们才是相同的。 Dash、ksh、bash、zsh 和至少一些 BusyBox 版本(但不是普通的 POSIX sh)都有一个-ef用于test测试以下内容的内置运算符:

[ "$path1" -ef "$path2" ]

这可以正确处理硬链接和符号链接(遵循符号链接,即将文件的符号链接视为与目标文件相同)。

如果您的 shell(或您的test实用程序)支持-ef.但请注意,它存在误报,因为并非所有文件系统都报告唯一的 inode 编号。例如,对于网络文件系统,您将受到远程主机对 inode 号的选择的支配。许多可堆叠文件系统报告底层 inode,如果底层目录树跨越多个文件系统,则该 inode 并不唯一。

一种不同的方法是检验可观察的等价性:修改其中一个目录,看看修改是否反映在另一个目录中。这种方法原则上不会出现误报,但它需要拥有修改目录的权限,并且可能会破坏系统中正在使用这些目录的其他部分。可能存在误报,因为看到反映的修改可能表明有一个守护进程正在非常快地同步目录。

答案3

sd(){       set '' "$1" '' "${2?sd() requires two arguments!}"
            while [ "$#" -gt 2 ]
            do    [  "${1:--L}" "${2:--L}" ${3:+"$4"} ] &&
                  [  "${1:--L}" ${3:+"-L"} "${3:-$4}" ] &&
                  [  "${2:-$3}" -ef "$4"/. ] && return  || ${1:+"return"}
                  set "$@" "$2";shift 2;set ! "$@"
            done  3>/dev/null 2>&"$((${#DBG}?2:3))"
    }

sd()首先检查它的两个参数是否都是符号链接,如果是,接下来检查这两个参数是否链接到具有相同 inode 和设备号的目录。如果是这样,sd() return那就是真的

如果失败,它会检查两者是否都是不是符号链接,以及,如果两者都是具有相同设备和索引节点号的目录。如果失败,则返回 false。

所以...

ln -s dir1 ln3; ln -s dir1 ln4; ln -s dir2 ln5

sd dir1 dir2; echo $?
1
sd dir1 ln3;  echo $?
1
sd ln4 ln3;   echo $?
0
sd ln4 ln5;   echo $?
1
mount --bind dir1 dir2
sd dir1 dir2; echo $?
0

最好不进行链接检查 - 例如,如果您想知道链接的目标是否与某个目录相同,或者根本不关心它是否是链接。在这种情况下,您只需要进行一次[ fname1 -ef fname2 ]测试。

哦,我想我还应该提到,这假设所有参数都有搜索权限。如果调用用户没有运行测试所需的权限,它将失败。

答案4

假设/home/username/app/home/username是目录,您无法检查 inode 号以查看它们是否是相同的路径。这是因为目录不能被硬链接,而软链接具有不同的索引节点。

您可以cd /home/usernametouch一个文件,并查看它是否出现在另一个文件中/app/home/username。可能有更好的方法,如果有人可以提供更好的答案,请继续。

相关内容