/my/dir
が同じパーティションにある/
かどうかを確認するにはどうすればよいですか?
これはスクリプト内での統合用です。バインドマウントは正しく処理する必要があります。POSIX互換のソリューションを歓迎します。
/my/dir
が同じパーティションにある/
かどうかを確認するにはどうすればよいですか?
これはスクリプト内での統合用です。バインドマウントは正しく処理する必要があります。POSIX互換のソリューションを歓迎します。
回答:
次のコマンドは、ファイルを含むマウントポイントの一意の名前を指定します$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
ユーティリティがありますが、その構文は異なります。
stat
は、st_dev
として呼び出されstat -c %D -- "$file"
たときにフィールドが報告されます。stat
GNU coreutilsと互換性のあるが含まれています。他の人stat
には%c
オプションがありません。使用できますstat -t -- "$file" | awk '{print $8}'
が、これが機能するのは、ファイル名に空白が含まれていない場合、またはstat -t -- "$file" | awk 'END {print $(NF-8)}'
任意のファイル名に対応しているがstat
出力にフィールドが将来追加されない場合のみです。stat
ユーティリティがありstat -f %d -- "$file"
ます。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
ベースのソリューションを使用することです。
df
デバイスの名前が何であれ、2つの呼び出し間で一貫しているため、比較しても問題ありません。
df
レポート/dev/sda6
とが/dev/disk/by-uuid/ca09b...
、どちらも同じデバイスを指しますが、マウントポイントが異なります。文字列比較テストは、各マウントポイントのファイルで試行すると明らかに失敗します。
mount /dev/sda6 /mnt1
その後にmount /dev/sda6 /mnt2
魅力的な機能が続きます。cat /proc/mounts
それで大丈夫です。ただし、ルートファイルシステムのデバイスとしてに/dev/disk/by-uuid/ca09b...
表示さdf
れるのは、Wheezy以降です。このsimlinkまたはUUID=ca09b...
マウント構文を使用してそれをさらにマウントしようとしても/dev/sda6
、何も表示されdf
なくなるわけではありません(起動プロセス中に何が行われたかを再現する方法はわかりませんが、ここでは関係ありません)。
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1
任意の数のパスで機能します。
$6
デバイス名($1
)ではなく、マウントポイント()をチェックしているので、問題ありません。
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 $?
。
これはバインドマウントでうまく機能しますが、ネットワークマウントではおそらく機能しません。