Czy dwa pliki są na stałe połączone?

27

Jak mogę sprawdzić, czy dwa pliki są na stałe połączone z linii poleceń? np. coś to łączy:

$ ls
fileA fileB fileC

$ is-hardlinked fileA fileB
yes

$ is-hardlinked fileA fileC
no
Vincent Scheib
źródło

Odpowiedzi:

37

W większości systemów plików¹ plik jest jednoznacznie określony przez jego numer i- węzła , więc wystarczy sprawdzić, czy dwa pliki mają ten sam numer i-węzła i są w tym samym systemie plików.

Ash, ksh, bash i zsh mają konstrukcję, która sprawdza za Ciebie: operator równości plików -ef.

[ fileA -ef fileB ] && ! [ fileA -ef fileC ]

W przypadku bardziej zaawansowanych przypadków ls -i /path/to/filewyświetla numer i-węzła pliku. df -P /path/to/filepokazuje, na jakim systemie plików znajduje się plik (jeśli dwa pliki znajdują się w tym samym katalogu, znajdują się w tym samym systemie plików). Jeśli twój system ma statpolecenie, prawdopodobnie może wyświetlać numery i-węzłów i systemu plików ( statróżni się w zależności od systemu, sprawdź dokumentację). Jeśli chcesz szybko rzucić okiem na twarde linki w katalogu, spróbuj ls -i | sort(być może potokowany do awk ).

¹ Wszystkie rodzime systemy plików unix i kilka innych, takich jak NTFS, ale prawdopodobnie nie egzotyczne przypadki, takie jak CramFS.

Gilles „SO- przestań być zły”
źródło
I zdecydowanie nie dotyczy niczego opartego na FAT, gdzie byłby wykrywany jako plik „usieciowany”.
Ignacio Vazquez-Abrams
4
Zauważ, że fileA -ef fileBzwraca również 0(sukces), jeśli fileAjest dowiązaniem symbolicznym fileBlub odwrotnie, lub oba łączą się do tego samego pliku.
janmoesen
jak faktycznie uruchomiłeś polecenie, które zasugerowałeś? Próbowałem [.bashrc -ef .bash / .bashrc] i jego odmian, ale tak naprawdę to nie działało.
Charlie Parker,
@CharlieParker [ .bashrc -ef .bash/.bashrc ]jest poprawny. Bez kontekstu oczywiście nie mam pojęcia, dlaczego tak naprawdę „nie działało” - możesz porównywać niewłaściwe pliki, możesz nie sprawdzać wyniku poprawnie, możesz używać powłoki bez -ef...
Gilles „SO- przestań być zły”
2
@CharlieParker Polecenie to jest [i jest synonimem test. Ale man [lub man testda ci stronę podręcznika zewnętrznego polecenia, podczas gdy prawie każda powłoka ma wbudowane polecenie z nieco innymi opcjami, więc musisz to sprawdzić w podręczniku powłoki.
Gilles „SO- przestań być zły”
4
function is-hardlinked() {
    r=yes
    [ "`stat -c '%i' $1`" != "`stat -c '%i' $2`" ] && r=no
    echo $r
}
x-way
źródło
6
Zauważ, że może to być wynik fałszywie dodatni, jeśli dwa pliki znajdują się w różnych systemach plików, ale mają ten sam i-węzeł. Musisz również przetestować numer urządzenia ( stat -c %d). A jeśli korzystasz z Linuksa (biorąc pod uwagę twoje statpolecenie), twoja powłoka musi [ fileA -ef fileB ]to wszystko zrobić bezpośrednio. Również twoje polecenie nie działa z nazwami plików zawierającymi białe znaki lub \[?*, lub zaczyna się od -: zawsze umieszczaj podwójne cudzysłowy wokół polecenia susbtitutions ( "$(stat -c %i -- "$1")").
Gilles „SO- przestań być zły”
1
Dlaczego miałbyś używać kilku nieporęcznych, ale przenośnych konstrukcji, a następnie rażąco nieprzenośne functionsłowo kluczowe o nazwie funkcji, które (ze względu na kreskę) narusza konwencje POSIX dotyczące dozwolonych nazw?
Charles Duffy
Zapomniałeś podać swoje $1i $2. Możesz także użyć $()składni zamiast odwrotnych znaków, ponieważ nawiasy wyjaśniają, gdzie zaczyna się i gdzie kończy polecenie, a zagnieżdżanie jest prostsze.
josch
3

Jak sugeruje pierwszy plakat, w Linuksie możesz napisać skrypt oparty na czymś takim:

stat -c '%i' fileA fileB fileC
Nie teraz
źródło
4
To nie wystarczy: otrzymasz ten sam numer dla dwóch plików, jeśli są one w różnych systemach plików, ale akurat mają tę samą i-węzeł. Musisz również przetestować numer urządzenia ( stat -c %d). A jeśli korzystasz z Linuksa (biorąc pod uwagę twoje statpolecenie), twoja powłoka musi [ fileA -ef fileB ]to wszystko zrobić bezpośrednio.
Gilles „SO- przestań być zły”
0

W GNU w find(1)wersji 4.2.11 lub nowszej możesz także użyć tego:

if [ "yes" = "$(find fileA -samefile fileB -exec echo yes \;)" ]; then
    echo yes
else
    echo no
fi

Jeśli fileAjest to ten sam plik, co fileBwtedy find, wydrukuje „tak” i warunek się spełni.

W przeciwieństwie do korzystania z operatora równości plików -efspowoduje to odrodzenie nowego procesu.

josch
źródło