Periksa apakah 2 direktori dihosting di partisi yang sama di Linux

9

Bagaimana saya bisa mengecek apakah /my/dirada di partisi yang sama /?

Ini untuk integrasi dalam skrip. Bind mounts harus ditangani dengan benar. Selamat datang solusi yang kompatibel dengan POSIX.

Totor
sumber
"Bind mounts harus ditangani dengan benar." Tapi apa yang Anda anggap benar? Pertanyaan Anda dapat ditafsirkan dengan cara baik.
Gilles 'SO- berhenti menjadi jahat'
@Gilles Dalam judul asli saya menulis "host" bukan "mount", seseorang diedit menambahkan IMHO kebingungan. Namun badan pertanyaan saya jelas: "pada partisi yang sama", yaitu pada partisi fisik yang sama, apa pun jalur atau titik mount yang digunakan untuk mengakses dua file / direktori.
Totor

Jawaban:

6

Anda dapat memeriksa ini dengan stat:

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

Menunjukkan nomor perangkat Anda dan tempat direktori Anda dipasang.


sumber
1
Bagus, tetapi statperintah shell bukan POSIX ...
Totor
Tidak? Bagaimana Anda tahu?
Tidak ada dalam daftar ini .
Totor
Oh, salahku. Tapi lain kali tunjukkan tautan ini sebelumnya.
5

Perintah berikut memberikan nama unik untuk titik pemasangan yang berisi file $file:

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

Ini berfungsi pada sistem POSIX apa pun . The -Ppilihan membebankan format diprediksi; bidang pertama dari baris kedua adalah "nama sistem file". Jadi, untuk memeriksa dua file berada di bawah titik pemasangan yang sama:

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

Atau, untuk menyimpan beberapa proses pemanggilan:

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

Beberapa sistem operasi dapat memiliki ruang dalam nama volume. Tidak ada cara yang sepenuhnya dapat diandalkan untuk mengurai dfoutput dalam kasus ini.

Di bawah tenda, Anda dapat mengidentifikasi sistem file yang berisi file menurut st_devbidang yang dikembalikan oleh stat. Tidak ada cara portabel untuk melakukan ini dari skrip shell. Beberapa sistem memiliki statutilitas, tetapi sintaks bervariasi:

  • Pada Linux yang tidak tertanam, Cygwin atau sistem lain dengan GNU coreutils, statmelaporkan st_devbidang ketika dipanggil sebagai stat -c %D -- "$file".
  • Beberapa instalasi BusyBox termasuk statyang kompatibel dengan GNU coreutils. Lain memiliki stattanpa %cpilihan; Anda dapat menggunakan stat -t -- "$file" | awk '{print $8}'tetapi ini hanya berfungsi jika nama file tidak mengandung spasi, atau stat -t -- "$file" | awk 'END {print $(NF-8)}'yang mengatasi dengan nama file yang sewenang-wenang tetapi tidak dengan penambahan bidang di masa depan untuk statoutput.
  • Sistem BSD memiliki statutilitas berbeda yang membutuhkan stat -f %d -- "$file".
  • Solaris, AIX dan lainnya tidak memiliki statutilitas.

Jika Perl tersedia, Anda dapat menggunakan

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

dan untuk melakukan perbandingan:

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

Perhatikan bahwa ada beberapa kasus sudut di mana hasil yang diinginkan tidak jelas. Sebagai contoh, dengan bind mount Linux, setelahnya mount --bind /foo /bar, /foodan /bardianggap sebagai sistem file yang sama. Selalu dimungkinkan bahwa kedua file tersebut sebenarnya terletak pada perangkat yang sama tetapi Anda tidak akan pernah tahu: misalnya, jika file berada di dua tunggangan jaringan yang berbeda, klien tidak memiliki cara untuk mengetahui apakah server mengekspor sistem file yang berbeda.

Jika file tersebut adalah direktori dan Anda dapat menulisnya, metode lain adalah membuat file sementara dan berusaha membuat tautan keras. Yang ini melaporkan hasil negatif di seluruh mount mengikat 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"
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Masalah: dftidak selalu memberikan nama perangkat, tetapi kadang-kadang symlink /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4membuatnya dftidak dapat diandalkan. Satu-satunya pilihan yang dapat diandalkan sejauh ini adalah menggunakan statsolusi berbasis.
Totor
@ Motor Itu tidak masalah: apa pun nama dfmelaporkan untuk perangkat, itu konsisten antara dua doa, jadi tidak apa-apa untuk perbandingan.
Gilles 'SANGAT berhenti menjadi jahat'
Tidak, itu tidak berhasil, saya mengujinya. Pada Debian Wheezy di sini, satu dflaporan /dev/sda6dan /dev/disk/by-uuid/ca09b..., keduanya merujuk ke perangkat yang sama, tetapi titik pemasangan berbeda. Uji perbandingan string jelas gagal ketika mencoba dengan file dari setiap titik pemasangan.
Totor
@ Motor Biasanya Anda tidak dapat memiliki perangkat blok yang sama dipasang dua kali. Seperti yang saya sebutkan dalam jawaban saya, ada kasus sudut seperti bind mount yang mungkin atau mungkin tidak dilaporkan berbeda.
Gilles 'SANGAT berhenti menjadi jahat'
Namun ia bekerja dengan sempurna pada Debian Squeeze dan Wheezy: mount /dev/sda6 /mnt1diikuti oleh mount /dev/sda6 /mnt2karya-karya seperti pesona. cat /proc/mountstidak masalah dengan itu. Namun, hanya sejak Wheezy yang /dev/disk/by-uuid/ca09b...ditampilkan dfsebagai perangkat untuk sistem file root. Upaya lebih lanjut untuk memasangnya menggunakan simlink ini atau UUID=ca09b...sintaks mount tidak berakhir menunjukkan apa pun selain /dev/sda6di df(saya tidak tahu bagaimana mereproduksi apa yang dilakukan selama proses boot, tapi itu bukan masalah di sini).
Totor
4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

Bekerja dengan sejumlah jalur.

n.st
sumber
Parsing output dfadalah tidak selalu ide yang baik .
Joseph R.
1
@ Motor saya memeriksa mountpoint ( $6), bukan nama perangkat ( $1), sehingga seharusnya tidak menjadi masalah.
n.st
1
@ JosephephR Itu yang terbaik yang ada di POSIX. n.st: mengapa tidak memeriksa bidang pertama? Tidak masalah jalur mana yang digunakan untuk mengakses perangkat, jika itu adalah titik pemasangan yang sama maka output akan konsisten.
Gilles 'SANGAT berhenti menjadi jahat'
Ini tidak berfungsi dengan bind mounts.
Totor
0

Solusi terbaik yang tersedia di POSIX adalah perbandingan ID perangkat file yang disediakan oleh fungsi stat (2) .

Perl memiliki fungsi stat yang sama dengan yang ditunjukkan Gilles :

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

tetapi "cara POSIX" adalah menggunakan program C seperti:

./checksamedev file1 file2

kode sumber yang mana adalah sebagai berikut:

#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;
}

Jika ID perangkat kedua file sama, mereka dihosting di sistem file yang sama, dalam hal ini, perintah di atas mengembalikan 0 (nilai lain jika tidak). Periksa dengan echo $?.

Ini berfungsi baik dengan bind mounts, tapi mungkin tidak dengan network mounts.

Totor
sumber