Linuxの同じパーティションで2つのディレクトリがホストされているかどうかを確認する


9

/my/dirが同じパーティションにある/かどうかを確認するにはどうすればよいですか?

これはスクリプト内での統合用です。バインドマウントは正しく処理する必要があります。POSIX互換のソリューションを歓迎します。


「バインドマウントは正しく処理する必要があります。」しかし、あなたは何を正しいと思いますか?あなたの質問はどちらの方法でも解釈できます。
ジル「SO-停止されて悪」

@Gilles元のタイトルでは、「mounted」ではなく「hosted」と書いて、誰かがIMHOの混乱を追加して編集しました。それでも私の質問の本文は明確です。「同じパーティション上」、つまり2つのファイルやディレクトリへのアクセスに使用されるパスやマウントポイントが何であれ、同じ物理パーティション上にあります。
Totor 2014

回答:


6

これはstatで確認できます。

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

デバイス番号とディレクトリがマウントされた場所を表示します。


1
いいですが、statシェルコマンドはPOSIXではありません...
Totor

番号?どうして知っていますか?

このリストにはありません。
Totor

ああ、悪い。ただし、次回はこのリンクを事前に表示してください。

5

次のコマンドは、ファイルを含むマウントポイントの一意の名前を指定します$file

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

これはどのPOSIXシステムでも機能します。この-Pオプションは、予測可能な形式を課します。2行目の最初のフィールドは「ファイルシステム名」です。したがって、2つのファイルが同じマウントポイントにあることを確認するには:

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。シェルスクリプトからこれを行うポータブルな方法はありません。一部のシステムにはstatユーティリティがありますが、その構文は異なります。

  • 非組み込みLinux、Cygwin、またはGNU coreutilsを備えたその他のシステムでstatは、st_devとして呼び出されstat -c %D -- "$file"たときにフィールドが報告されます。
  • 一部のBusyBoxインストールには、statGNU 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は同じファイルシステムと見なされます。2つのファイルが実際に同じデバイス上にある可能性は常にありますが、決してわかりません。たとえば、ファイルが2つの異なるネットワークマウントにある場合、クライアントはサーバーが異なるファイルシステムをエクスポートしているかどうかを知る方法がありません。

ファイルがディレクトリであり、それらに書き込むことができる場合、別の方法は一時ファイルを作成してハードリンクを作成することです。これは、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ベースのソリューションを使用することです。
トーター、2014

@Totorそれは問題ではありません。dfデバイスの名前が何であれ、2つの呼び出し間で一貫しているため、比較しても問題ありません。
Gilles「SO-邪悪なことをやめよう」

いいえ、動作しません。テストしました。ここのDebian Wheezyでは、1つのdfレポート/dev/sda6とが/dev/disk/by-uuid/ca09b...、どちらも同じデバイスを指しますが、マウントポイントが異なります。文字列比較テストは、各マウントポイントのファイルで試行すると明らかに失敗します。
Totor 2014

@Totor通常、同じブロックデバイスを2回マウントすることはできません。私の回答で指摘しているように、バインドマウントなど、個別として報告される場合と報告されない場合のあるまれなケースがあります。
Gilles「SO-邪悪なことをやめよう」14

それでも、Debian SqueezeとWheezyで完全に機能します。mount /dev/sda6 /mnt1その後にmount /dev/sda6 /mnt2魅力的な機能が続きます。cat /proc/mountsそれで大丈夫です。ただし、ルートファイルシステムのデバイスとしてに/dev/disk/by-uuid/ca09b...表示さdfれるのは、Wheezy以降です。このsimlinkまたはUUID=ca09b...マウント構文を使用してそれをさらにマウントしようとしても/dev/sda6、何も表示されdfなくなるわけではありません(起動プロセス中に何が行われたかを再現する方法はわかりませんが、ここでは関係ありません)。
Totor 2014

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

任意の数のパスで機​​能します。


の出力を解析することは必ずしも良い考えdfはありません
ジョセフR.

1
@Totor $6デバイス名($1)ではなく、マウントポイント()をチェックしているので、問題ありません。
n.st 2014年

1
@JosephR POSIXで最高です。n.st:最初のフィールドをチェックしてみませんか?デバイスへのアクセスにどのパスを使用したかは関係ありません。同じマウントポイントであれば、出力は一貫しています。
Gilles「SO-邪悪なことをやめ

これはバインドマウントでは機能しません。
Totor 2014

0

POSIXで利用できる最も確実なソリューションは、stat(2)関数によって提供されるファイルのデバイスIDの比較です。

PerlはGillesが指摘したのと同様のstat関数を持っています

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

これはバインドマウントでうまく機能しますが、ネットワークマウントではおそらく機能しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.