Sprawdź, czy 2 katalogi są hostowane na tej samej partycji w systemie Linux

9

Jak mogę sprawdzić, czy /my/dirjest na tej samej partycji co /?

Ma to na celu integrację ze skryptem. Mocowania do wiązania powinny być obsługiwane poprawnie. Rozwiązania zgodne z POSIX są mile widziane.

Totor
źródło
„Mocowania do opraw powinny być obsługiwane poprawnie”. Ale co uważasz za prawidłowe? Twoje pytanie może być interpretowane w obie strony.
Gilles „SO- przestań być zły”
@Gilles W oryginalnym tytule napisałem „hostowany” zamiast „montowany”, ktoś edytował, dodając zamieszanie IMHO. Jednak moje pytanie jest jasne: „na tej samej partycji”, czyli na tej samej partycji fizycznej, bez względu na ścieżkę lub punkt montowania użyty do uzyskania dostępu do dwóch plików / katalogów.
Totor

Odpowiedzi:

6

Możesz to sprawdzić za pomocą statystyki:

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

Wyświetla numer urządzenia i miejsce zamontowania katalogu.


źródło
1
Fajnie, ale statpolecenie powłoki nie jest POSIX ...
Totor
Nie? Skąd wiesz?
Nie ma na tej liście .
Totor
Och, mój zły. Ale następnym razem pokaż ten link z góry.
5

Następujące polecenie podaje unikalną nazwę punktu podłączenia zawierającego plik $file:

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

Działa to na każdym systemie POSIX . -POpcja nakłada przewidywalnego formatu; pierwsze pole drugiego wiersza to „nazwa systemu plików”. Tak więc, aby sprawdzić, czy dwa pliki znajdują się w tym samym punkcie montowania:

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

Lub, aby zapisać kilka wywołań procesów:

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

Kilka systemów operacyjnych może mieć spacje w nazwach woluminów. W dftym przypadku nie ma całkowicie niezawodnego sposobu analizowania danych wyjściowych.

Pod maską możesz zidentyfikować system plików zawierający plik po st_devpolu zwróconym przez stat. Nie ma przenośnego sposobu na zrobienie tego ze skryptu powłoki. Niektóre systemy mają statnarzędzie, ale jego składnia jest różna:

  • W niewbudowanym systemie Linux, Cygwin lub innym systemie z GNU coreutils statzgłasza st_devpole po wywołaniu jako stat -c %D -- "$file".
  • Niektóre instalacje BusyBox obejmują takie, statktóre są kompatybilne z coreutils GNU. Inni mają statbez %copcji; możesz użyć, stat -t -- "$file" | awk '{print $8}'ale działa to tylko wtedy, gdy nazwa pliku nie zawiera spacji lub stat -t -- "$file" | awk 'END {print $(NF-8)}'która kopiuje z dowolnymi nazwami plików, ale nie z przyszłymi dodatkami pól do danych statwyjściowych.
  • Systemy BSD mają inne statnarzędzie, które wymaga stat -f %d -- "$file".
  • Solaris, AIX i inne nie mają żadnego statnarzędzia.

Jeśli Perl jest dostępny, możesz użyć

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

i do porównania:

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

Należy pamiętać, że istnieją przypadki narożne, w których pożądany wynik nie jest jasny. Na przykład, z powiązań wierzchowców Linuksa, po mount --bind /foo /bar, /fooi /barsą uważane za tym samym systemie plików. Zawsze jest możliwe, że oba pliki znajdują się na tym samym urządzeniu, ale nigdy się nie dowiesz: na przykład, jeśli pliki znajdują się na dwóch różnych podłączeniach sieciowych, klient nie ma możliwości sprawdzenia, czy serwer eksportuje różne systemy plików.

Jeśli pliki są katalogami i można do nich pisać, inną metodą jest utworzenie pliku tymczasowego i próba utworzenia twardego łącza. Ten raport podaje negatywny wynik w przypadku podłączeń do linuksa.

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 „SO- przestań być zły”
źródło
Problem: dfnie zawsze podać nazwę urządzenia, ale kiedyś się dowiązania do niego jakby /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4co dfnie są wiarygodne. Jedyną dotychczas niezawodną opcją jest zastosowanie statrozwiązania opartego na bazie .
Totor
@Totor To nie ma znaczenia: bez względu na nazwę dfurządzenia, jest ono spójne między dwoma wywołaniami, więc można je porównać.
Gilles „SO- przestań być zły”
Nie, to nie działa, przetestowałem to. Na Debian Wheezy tutaj pojedynczy dfraport /dev/sda6i /dev/disk/by-uuid/ca09b...oba odnoszą się do tego samego urządzenia, ale różne punkty montowania. Test porównania ciągów oczywiście kończy się niepowodzeniem podczas próby z plikami z każdego punktu montowania.
Totor
@Totor Zwykle nie można zamontować tego samego urządzenia blokowego dwa razy. Jak wskazuję w mojej odpowiedzi, istnieją przypadki narożne, takie jak łączniki, które mogą, ale nie muszą być zgłaszane jako odrębne.
Gilles „SO- przestań być zły”
Jednak działa idealnie w Debian Squeeze i Wheezy: mount /dev/sda6 /mnt1a następnie mount /dev/sda6 /mnt2działa jak urok. cat /proc/mountsjest z tym w porządku. Jednak dopiero od czasu, gdy Wheezy /dev/disk/by-uuid/ca09b...jest pokazany dfjako urządzenie dla głównego systemu plików. Dalsze próby montowania go za pomocą tego linku prostego lub UUID=ca09b...składni montowania nie kończą się pokazywaniem niczego innego niż /dev/sda6w df(nie wiem, jak odtworzyć to, co zrobiono podczas procesu rozruchu, ale nie o to tu chodzi).
Totor
4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

Działa z dowolną liczbą ścieżek.

n.st
źródło
Parsowania wyjście dfto nie zawsze jest dobrym pomysłem .
Joseph R.
1
@Totor Sprawdzam mountpoint ( $6), a nie nazwę urządzenia ( $1), więc nie powinno to stanowić problemu.
n.
1
@JosephR To najlepsze, co jest w POSIX. n.st: dlaczego nie sprawdzić pierwszego pola? Nie ma znaczenia, która ścieżka została użyta do uzyskania dostępu do urządzenia, jeśli jest to ten sam punkt montowania, wynik będzie spójny.
Gilles „SO- przestań być zły”
To nie działa z mocowaniami łączenia.
Totor
0

Najlepszym niezawodnym rozwiązaniem dostępnym w POSIX jest porównanie identyfikatorów urządzeń plików dostarczonych przez funkcję stat (2) .

Perl ma podobną funkcję statystyczną, jak zauważył Gilles :

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

ale „sposobem POSIX” jest użycie programu C, takiego jak:

./checksamedev file1 file2

który kod źródłowy jest następujący:

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

Jeśli identyfikatory urządzeń obu plików są równe, są one hostowane w tym samym systemie plików, w którym to przypadku powyższe polecenia zwracają 0 (w przeciwnym razie inna wartość). Sprawdź za pomocą echo $?.

Działa to dobrze z mocowaniami łączenia, ale prawdopodobnie nie będzie z mocowaniami sieciowymi.

Totor
źródło