Ustalanie, czy plik jest dowiązaniem twardym czy dowiązaniem symbolicznym?

51

Tworzę skrypt powłoki, który pobierze nazwę pliku / ścieżkę do pliku i określi, czy plik jest dowiązaniem symbolicznym, czy dowiązaniem twardym.

Jedyną rzeczą jest to, że nie wiem, jak sprawdzić, czy są twardym łączem. Utworzyłem 2 pliki, jeden twardy i drugi symboliczny, do użycia jako plik testowy. Ale jak mam ustalić, czy plik jest dowiązaniem twardym czy symbolicznym w skrypcie powłoki?

Jak znaleźć partycję docelową łącza symbolicznego? Powiedzmy, że mam plik, który prowadzi do innej partycji, jak znaleźć ścieżkę do tego oryginalnego pliku?

k-Rocker
źródło
16
Co rozumiesz przez twardy link? Wszystkie pliki są twardymi linkami.
terdon
1
@terdon ln /foo/bar/ /foo/bar2tworzy hardlink, podczas gdy ln -s /foo/bar /foo/bar2tworzy symlink, czy to miał na myśli?
DisplayName,
14
@DisplayName tak, ale wszystkie pliki są twardymi linkami do ich i-węzłów. Tak działają systemy plików Linux. W przykładzie, bar2i barto zarówno dowiązania twarde, tylko wskazując na samego węzła.
terdon
10
@DisplayName tak, są twardymi linkami do innych i- węzłów . Tutaj nie ma sprzeczności. Plik jest linkiem do i-węzła. To jest definicja pliku. W twoim przypadku masz te linki w różnych miejscach, ale to nie zmienia podstawowej struktury danych. Chodzi mi o to, że zarówno bari bar2są równie ważne. Jedno nie jest łączem z drugim, oba są łączami, ale wskazują ten sam i-węzeł.
terdon
3
@Scott nie, mówię, że zwykłe pliki są dowiązaniami twardymi i że utworzone dowiązania twarde lnnie różnią się od zwykłych plików.
terdon

Odpowiedzi:

42

Odpowiedź Jima wyjaśnia jak testować na miejsce linku: za pomocą test„s -Ltest.

Ale testowanie pod kątem „twardego linku” nie jest tym, czego chcesz. Twarde linki działają ze względu na to, jak Unix obsługuje pliki: każdy plik jest reprezentowany przez pojedynczy i-węzeł. Wówczas pojedynczy i-węzeł ma zero lub więcej nazw lub pozycji katalogu lub, technicznie rzecz biorąc, twardych linków (co nazywasz „plikiem”).

Na szczęście statpolecenie, jeśli jest dostępne, może powiedzieć, ile nazw ma i-węzeł.

Więc szukasz czegoś takiego (tutaj przy założeniu implementacji GNU lub busybox stat):

if [ "$(stat -c %h -- "$file")" -gt 1 ]; then
    echo "File has more than one name."
fi

-c '%h'Trochę mówi statpo prostu wyjście liczbę hardlinki do węzła, czyli liczba nazw plik. -gt 1następnie sprawdza, czy jest to więcej niż 1.

Zauważ, że dowiązania symboliczne, podobnie jak wszystkie inne pliki, mogą być również połączone z kilkoma katalogami, więc możesz mieć kilka dowiązań twardych do jednego dowiązania symbolicznego.

derobert
źródło
ok, dla jasności mogę wyprowadzić liczbę twardych dowiązań, które plik ma za pomocą polecenia stat, a jeśli jest większy niż 1, to ma inny plik połączony gdzieś na partycji.
k-Rocker
@ k-Rocker Tak. To ma drugą nazwę gdzieś na partycji.
derobert
1
W OS X lub * BSD to jest stat -f %l /path/to/file. Możesz także użyć, gstat -c %h /path/to/filejeśli masz zainstalowane jądra GNU bez ich domyślnych nazw (z Homebrew na OS X).
GDP2
29

Przykład:

$ touch f1
$ ln f1 f2
$ ln f1 f3
$ ln -s f1 s1
$ ln -s f2 s2
$ ln -s ./././f3 s3
$ ln -s s3 s4
$ ln s4 s5
$ ls -li
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802345 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s1 -> f1
10802346 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s2 -> f2
10802347 lrwxrwxrwx 1 stephane stephane 8 Nov 12 19:56 s3 -> ./././f3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s4 -> s3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s5 -> s3

Te f1, f2oraz f3wpisy w katalogach są takie same plik (samo-węzła: 10802124, zauważysz liczbę linków jest 3). Są to twarde łącza do tego samego zwykłego pliku.

s4i s5są również tym samym plikiem (10802384). Są one typu dowiązanie symboliczne , a nie regularne . Wskazują tutaj ścieżkę s3. Ponieważ s4i s5są wpisami tego samego katalogu, ta ścieżka względna s3wskazuje na ten sam plik (ten z inod 10802347) dla obu.

Jeśli to zrobisz ls -Ll, poprosi o uzyskanie informacji o pliku po rozwiązaniu dowiązań symbolicznych:

$ ls -lLi
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s4
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s5

Przekonasz się, że wszystkie rozwiązują ten sam plik (10802124).

Możesz sprawdzić, czy plik jest dowiązaniem symbolicznym [ -L file ]. Podobnie możesz przetestować, czy plik jest zwykłym plikiem [ -f file ], ale w takim przypadku sprawdzenie jest wykonywane po rozwiązaniu dowiązań symbolicznych.

dowiązania twarde nie są rodzajem pliku, są po prostu różnymi nazwami pliku (dowolnego typu).

Stéphane Chazelas
źródło
19

Za pomocą operatorów -hi polecenia:-Ltest

-h file 
true if file is a symbolic link

-L file 
true if file is a symbolic link

http://www.mkssoftware.com/docs/man1/test.1.asp

Zgodnie z tym wątkiem SO mają takie samo zachowanie, ale -Ljest preferowane.

jimm-cl
źródło
ok fajnie, ale co z twardymi linkami? sprawdziłem bieżnik, ale nic o twardych linkach. Jeśli -L zwraca false, czy to oznacza, że ​​jest to twardy link? czy zwykły plik?
k-Rocker
1
Twarde linki mają to samo inode. Ponadto miękkie linki pokazują lna początku danych ls -lwyjściowych ... Myślę, że możesz połączyć te reguły w skrypcie, a także [[ -L file ]]sprawdzić, czy dany plik jest miękki czy trudny .
jimm-cl
ok, jak również znaleźć docelową partycję dowiązania symbolicznego?
k-Rocker
3

Istnieje wiele całkiem poprawnych odpowiedzi, ale nie sądzę, aby ktokolwiek tak naprawdę zajął się pierwotnym błędnym postrzeganiem. Pierwotne pytanie brzmi: „kiedy tworzę dowiązanie symboliczne, łatwo jest je później zidentyfikować. Ale nie mogę wymyślić, jak zidentyfikować dowiązanie twarde”. I tak, odpowiedzi w zasadzie sprowadzają się do „nie możesz” i mniej więcej wyjaśniają dlaczego, ale wydaje się, że nikt nie przyznał, że tak naprawdę jest to mylące i dziwne.

Jeśli czytasz to wszystko i zorientowałeś się, co się dzieje, to jesteś dobry; nie musisz czytać mojego małego. Jeśli nadal jesteś zdezorientowany, kontynuuj.

Naprawdę bardzo krótka odpowiedź brzmi: twardy link wcale nie jest tak naprawdę linkiem, a nie takim, jak link symboliczny. Jest to nowy wpis w strukturze katalogów, który wskazuje na tę samą wiązkę bajtów, co oryginalny wpis w katalogu, a kiedy go utworzysz, jest on równie „prawdziwy” i legalny jak pierwszy. Każdy „normalny” plik na dysku ma co najmniej jeden twardy link; bez tego nie zobaczyłbyś tego w żadnymkatalogu i nie będzie mógł się do niego odwoływać ani go używać. Więc jeśli masz plik Fred.txt i łączysz do niego Wilma.txt i Barney.txt, wszystkie trzy nazwy (i wpisy katalogu) odnoszą się do tego samego pliku i wszystkie są jednakowo prawidłowe. System operacyjny nie może powiedzieć, że jeden z wpisów został utworzony po naciśnięciu przycisku „zapisz” w edytorze tekstu, a pozostałe zostały wykonane za pomocą polecenia „ln”.

System operacyjny nie trzeba śledzić, jak wiele różnych wpisy są skierowane do tego samego pliku, choć. Jeśli usuniesz plik Wilma.txt, nic dziwnego, że nie zwolnisz miejsca na dysku. Ale jeśli usuniesz Fred.txt („oryginalny” plik), nadal nie zwolnisz miejsca na dysku, ponieważ dane na dysku, które były znane jako Fred.txt, nadal są również Barney.txt. Dopiero po usunięciu wszystkich pozycji katalogu system operacyjny przydzieli miejsce zajmowane przez dane.

Gdyby Barney.txt był dowiązaniem symbolicznym, usunięcie Fred.txt spowodowałoby zwolnienie miejsca, a Barney.txt byłby teraz uszkodzonym łączem. Ponadto, jeśli przeniesiesz lub zmienisz nazwę pliku, który wskazuje na niego dowiązanie symboliczne, przerwiesz to łącze. Ale możesz przenieść lub zmienić nazwę pliku, na który chcesz na stałe, bez naruszania innych pozycji katalogu wskazujących na ten plik / dane, ponieważ wszystkie z nich są pozycjami katalogu, które odnoszą się do tego samego bloku danych na dysku (za pomocą i-węzeł # tych danych).

[To dwa lata później, a to ostatnie trochę mnie zdezorientowało , więc myślę, że wyjaśnię. Jeśli wpiszesz „mv ./Wilma.txt ../elsewhere/Betty.txt”, wygląda na to, że przenosisz plik, ale tak naprawdę nie jest. Naprawdę robisz to, usuwając element z listy katalogu bieżącego katalogu, który mówi „nazwa„ Wilma.txt ”jest powiązany z danymi, które można znaleźć za pomocą i-węzła ###### # ”i dodanie nowego elementu wiersza do listy katalogów katalogu ../elsewhere, który mówi„ nazwa Betty.txt ”jest powiązana z danymi, które można znaleźć za pośrednictwem i-węzła #######”. Dlatego możesz „przenieść” plik 2 gigabajty tak szybko, jak plik 2 kilobajty, o ile przenosisz je w inne miejsce na tym samym dysku.]

Ponieważ system operacyjny musi śledzić ilu różne wpisy w katalogach są skierowane do tej samej porcji danych, to można stwierdzić, czy dany plik został ciężko związana, chociaż nie można powiedzieć na pewno, jeśli wpis katalogu, który „patrzysz na to” jest oryginalny, czy nie. Jednym ze sposobów jest polecenie „ls”, a konkretnie „ls -l” (to jest małe litery L po myślniku)

Aby pożyczyć wcześniejszy przykład ...

 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1

Pierwsza litera to myślnik, więc nie jest to katalog ani coś egzotycznego, to zwykły zwykły plik. Ale gdyby było to naprawdę zwyczajne, liczba ta po części rwx wynosiłaby „1”, jak w „istnieje jeden wpis katalogu wskazujący na ten blok danych”. Ale to część demonstracji twardych linków, więc zamiast tego jest napisane „3”.

Zauważ, że może to prowadzić do dziwnych i tajemniczych zachowań (to znaczy, jeśli nie owinąłeś głowy twardymi linkami). Jeśli otworzysz Fred.txt w edytorze tekstu i wprowadzisz jakieś zmiany, czy zobaczysz te same zmiany w Wilma.txt i Barney.txt? Może. Prawdopodobnie. Jeśli twój edytor tekstowy zapisze zmiany, otwierając oryginalny plik i zapisując zmiany, wówczas tak, wszystkie trzy nazwy będą nadal wskazywać ten sam (nowo zmieniony) tekst. Ale jeśli edytor tekstu utworzy nowy plik (Fred-new-temp.txt), zapisze w nim zmienioną wersję, następnie usunie Fred.txt, a następnie zmieni nazwę Fred-new-temp.txt na Fred.txt, Wilma i Barney nadal wskazuje oryginalną wersję, a nie nową zmienioną wersję. Jeśli nie rozumiesz twardych linków, może to doprowadzić cię do szału. :) [Okej, właściwie nie znam żadnychedytory tekstów, które zrobiłyby nowy plik / zmiana nazwy, ale znam wiele innych programów, które robią to dokładnie, więc bądź czujny.]

Ostatnia uwaga: jedną z rzeczy, które sprawdza „fsck” (kontrola systemu plików), jest to, czy na twoim dysku znajdują się bloki danych, do których w jakiś sposób nie odwołują się żadne wpisy katalogu. Czasami coś idzie nie tak i jedyny wpis katalogu wskazujący na i-węzeł zostaje usunięty, ale samo miejsce na dysku nie jest oznaczone jako „dostępne”. Jednym z zadań fsck jest dopasowanie całego przydzielonego miejsca do wszystkich pozycji katalogu, aby upewnić się, że nie ma żadnych plików, do których nie ma odnośników. Jeśli coś znajdzie, tworzy nowe pozycje katalogu i umieszcza je w „lost + found”.

Snarke
źródło
Zastanawiam się, jakie są „inne programy, które to dokładnie robią”?
phk
@ phk Nie wiem, o czym konkretnie myśli, ale jest to dość powszechne podejście do wykonywania działań, które mogą zająć dużo czasu i pozostawiają cię w niepewnym stanie, jeśli się nie powiedzie. Na przykład, jeśli spróbujesz pobrać ze zdalnego serwera i wiesz, że istnieje prawdopodobieństwo, że serwer może przekroczyć limit czasu, wówczas jednym z podejść byłoby pobranie całej zawartości do pliku tymczasowego. W ten sposób, jeśli coś pójdzie nie tak podczas pobierania, nadal masz oryginalny plik.
cwallenpoole,
Jedynym programem, który znam na pewno, jest FreeHand, ponieważ jeśli / kiedy zawiesi się podczas zapisywania, pozostanie plik tymczasowy, a nie zniekształcony oryginalny plik. Ale widziałem też, że robią to inne programy; Obecnie nie mogę podać konkretnych przykładów.
Snarke
2

możesz użyć readlink FILE; echo $?. Zwraca 1, gdy jest to dowiązanie twarde, a 0, gdy jest dowiązanie symboliczne.

Ze strony podręcznika: „Przy wywołaniu jako readlink drukowany jest tylko cel dowiązania symbolicznego. Jeśli podany argument nie jest dowiązaniem symbolicznym, readlink nic nie wydrukuje i zakończy się z błędem.”

użytkownik2103720
źródło