检查Linux上是否在同一分区上托管2个目录


9

如何检查是否/my/dir与属于同一分区/

这是为了集成到脚本中。绑定安装架应正确处理。欢迎使用POSIX兼容解决方案。


“内衬必须正确处理。” 但是您认为正确的是什么?您的问题可以用任何一种方式解释。
吉尔(Gilles)'所以

@Gilles在最初的标题中,我写了“托管”而不是“挂载”,有人编辑添加了困惑,恕我直言。但是我的问题很清楚:“在同一分区上”,即在同一物理分区上,无论用于访问两个文件/目录的路径或挂载点如何。
Totor 2014年

Answers:


6

您可以使用stat检查此内容:

$ stat -c '%d %m' /proc/sys/
3 /proc

显示设备号和目录的安装位置。


1
很好,但是statshell命令不是POSIX ...
Totor 2014年

没有?你怎么知道的?

不在此列表中
Totor

哦,我的坏。但是下一次请提前显示此链接。

5

以下命令为包含该文件的安装点提供了唯一的名称$file

df -P -- "$file" | awk 'NR==2 {print $1}'

这适用于任何POSIX系统。该-P选项强加了可预测的格式;第二行的第一个字段是“文件系统名称”。因此,要检查两个文件是否在同一安装点下:

if [ "$(df -P -- "$file1" | awk 'NR==2 {print $1}')" = \
     "$(df -P -- "$file2" | awk 'NR==2 {print $1}')" ]; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

或者,要保存几个流程调用:

if df -P -- "$file1" "$file2" |
   awk 'NR!=1 {dev[NR] = $1} END {exit(dev[2] != dev[3])}'; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

一些操作系统的卷名中可以有空格。df在这种情况下,没有完全可靠的方法来解析输出。

在后台,您可以通过st_dev返回的字段来标识包含文件的文件系统stat。从shell脚本没有可移植的方法来执行此操作。某些系统具有stat实用程序,但是其语法有所不同:

  • 在非嵌入式Linux,Cygwin或其他具有GNU coreutils的系统上,当以调用时,将stat报告该st_dev字段stat -c %D -- "$file"
  • 一些BusyBox安装中包含stat与GNU coreutils兼容的。其他人则stat没有%c选择权;您可以使用,stat -t -- "$file" | awk '{print $8}'但是仅当文件名不包含空格,或者stat -t -- "$file" | awk 'END {print $(NF-8)}'可以处理任意文件名但不能处理将来在stat输出中添加字段时,此方法才有效。
  • BSD系统有不同的stat实用需要stat -f %d -- "$file"
  • Solaris,AIX和其他没有stat实用程序。

如果有Perl,则可以使用

perl -e 'print ((stat($ARGV[0]))[0])' -- "$file"

并进行比较:

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- "$file1" "$file2"

请注意,在某些极端情况下,所需的结果尚不清楚。例如,使用Linux的绑定安装,后mount --bind /foo /bar/foo/bar被认为是同一个文件系统。这两个文件实际上总是可能位于同一台设备上,但是您永远不会知道:例如,如果文件位于两个不同的网络安装上,则客户端将无法知道服务器是否在导出不同的文件系统。

如果文件是目录并且可以写入文件,则另一种方法是创建一个临时文件并尝试建立硬链接。这个报告在Linux绑定安装中报告了负面结果。

tmp1=$(TMPDIR=$dir1 mktemp)
tmp2=$(TMPDIR=$dir2 mktemp)
if ln -f -- "$tmp1" "$tmp2"; then
  echo "$dir1 and $dir2 are on the same filesystem, which supports hard links"
fi
rm -f "$tmp1" "$tmp2"

问题:df并不总是提供设备名称,但有时会对其进行符号链接,例如/dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4使其df不可靠。到目前为止,唯一可靠的选择是使用stat基于-解决方案。
Totor 2014年

@Totor没关系:无论df设备报告的名称是什么,两次调用之间的名称都是一致的,因此可以进行比较。
吉尔(Gilles)'所以

不,它不起作用,我测试过。在此处的Debian Wheezy上,单个df报告/dev/sda6/dev/disk/by-uuid/ca09b...均指同一设备,但挂载点不同。尝试从每个安装点尝试文件时,字符串比较测试显然失败。
Totor 2014年

@Totor通常,您不能两次安装同一块设备。正如我在回答中指出的那样,有些极端情况(例如绑定安装)可能会或可能不会被报告为不同。
吉尔斯(Gilles)'所以

然而,它在Debian Squeeze和Wheezy上运行完美:mount /dev/sda6 /mnt1其次mount /dev/sda6 /mnt2是魅力。cat /proc/mounts很好。但是,仅由于Wheezy /dev/disk/by-uuid/ca09b...被显示df为根文件系统的设备。进一步尝试使用此simlink或UUID=ca09b...mount语法来装载它,除了/dev/sda6df(in 不知道如何重现它在引导过程中所做的事情之外,其他什么都不会结束)之外,其他事情都没有结束。
Totor 2014年

4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

适用于任何数量的路径。



1
@Totor我正在检查安装点($6),而不是设备名称($1),所以这应该不是问题。
2014年

1
@JosephR这是POSIX中最好的。n.st:为什么不检查第一个字段?使用哪个路径访问设备都没有关系,如果它是相同的安装点,则输出将保持一致。
吉尔(Gilles)'所以

这不适用于绑定安装。
Totor

0

POSIX中最好的万无一失的解决方案是比较stat(2)函数提供的文件的设备ID

Perl中也有类似的统计功能,吉尔 指出

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- file1 file2

但是“ POSIX方式”是使用C程序,例如:

./checksamedev file1 file2

哪些源代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    struct stat s1, s2;
    if( argc==3 && lstat(argv[1], &s1)==0 && lstat(argv[2], &s2)==0 )
        return !(s1.st_dev == s2.st_dev);
    return 2;
}

如果两个文件的设备ID相等,则它们将托管在同一文件系统上,在这种情况下,以上命令将返回0(否则返回另一个值)。用检查echo $?

这在绑定安装上很好用,但可能不适用于网络安装。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.