biegnę
ln /a/A /b/B
Chciałbym zobaczyć w folderze a
gdzie punkty złożyć do przez ls
.
biegnę
ln /a/A /b/B
Chciałbym zobaczyć w folderze a
gdzie punkty złożyć do przez ls
.
Odpowiedzi:
Możesz znaleźć numer i-węzła dla swojego pliku za pomocą
ls -i
i
ls -l
pokazuje liczbę referencji (liczba dowiązań twardych do konkretnego i-węzła)
po znalezieniu numeru i-węzła możesz wyszukać wszystkie pliki z tym samym i-węzłem:
find . -inum NUM
pokaże nazwy plików dla i-węzła NUM w bieżącym katalogu (.)
Naprawdę nie ma dobrze zdefiniowanej odpowiedzi na twoje pytanie. W przeciwieństwie do dowiązań symbolicznych, dowiązania twarde są nie do odróżnienia od „oryginalnego pliku”.
Pozycje katalogu składają się z nazwy pliku i wskaźnika do i-węzła. Z kolei i-węzeł zawiera metadane pliku i (wskazuje na) rzeczywistą zawartość pliku). Utworzenie twardego łącza tworzy kolejną nazwę pliku + odniesienie do tego samego i-węzła. Odwołania te są jednokierunkowe (przynajmniej w typowych systemach plików) - i-węzeł zachowuje tylko liczbę odwołań. Nie ma wewnętrznego sposobu, aby dowiedzieć się, która jest „oryginalną” nazwą pliku.
Nawiasem mówiąc, właśnie dlatego wywoływane jest systemowe wywołanie w celu „usunięcia” pliku unlink
. Po prostu usuwa twardy link. I-węzeł dołączone dane są usuwane tylko wtedy, gdy liczba referencyjna i-węzła spadnie do 0.
Jedynym sposobem na znalezienie innych odniesień do danego i-węzła jest dokładne przeszukanie systemu plików i sprawdzenie, które pliki odnoszą się do danego i-węzła. Aby wykonać to sprawdzenie, możesz użyć „testu A –ef B” ze powłoki.
UNIX ma dowiązania twarde i dowiązania symboliczne (odpowiednio wykonane "ln"
i "ln -s"
). Dowiązania symboliczne to po prostu plik, który zawiera rzeczywistą ścieżkę do innego pliku i może przechodzić przez systemy plików.
Twarde linki istnieją już od najwcześniejszych dni UNIX (które i tak pamiętam, i to już od dawna). Są to dwa wpisy katalogu, które odnoszą się dokładnie do tych samych podstawowych danych. Dane w pliku są określone przez jego inode
. Każdy plik w systemie plików wskazuje na i-węzeł, ale nie ma wymogu, aby każdy plik wskazywał na unikalny i-węzeł - stąd pochodzą twarde łącza.
Ponieważ i-węzły są unikalne tylko dla danego systemu plików, istnieje ograniczenie, że dowiązania twarde muszą znajdować się w tym samym systemie plików (w przeciwieństwie do dowiązań symbolicznych). Zauważ, że w przeciwieństwie do dowiązań symbolicznych, nie ma pliku uprzywilejowanego - wszystkie są równe. Obszar danych zostanie zwolniony tylko wtedy, gdy wszystkie pliki korzystające z tego i-węzła zostaną usunięte (i wszystkie procesy również go zamkną, ale to inny problem).
Możesz użyć "ls -i"
polecenia, aby uzyskać i-węzeł określonego pliku. Następnie możesz użyć "find <filesystemroot> -inum <inode>"
polecenia, aby znaleźć wszystkie pliki w systemie plików z danym i-węzłem.
Oto skrypt, który właśnie to robi. Wywołujesz to za pomocą:
findhardlinks ~/jquery.js
i znajdzie wszystkie pliki w tym systemie plików, które są twardymi dowiązaniami do tego pliku:
pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
'/home/pax/jquery.js' has inode 5211995 on mount point '/'
/home/common/jquery-1.2.6.min.js
/home/pax/jquery.js
Oto skrypt.
#!/bin/bash
if [[ $# -lt 1 ]] ; then
echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
exit 1
fi
while [[ $# -ge 1 ]] ; do
echo "Processing '$1'"
if [[ ! -r "$1" ]] ; then
echo " '$1' is not accessible"
else
numlinks=$(ls -ld "$1" | awk '{print $2}')
inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
device=$(df "$1" | tail -1l | awk '{print $6}')
echo " '$1' has inode ${inode} on mount point '${device}'"
find ${device} -inum ${inode} 2>/dev/null | sed 's/^/ /'
fi
shift
done
. ./findhardlinks.bash
bycia w Zsh OS X. Moje bieżące okno na ekranie zostanie zamknięte.
INUM=$(stat -c %i $1)
. Również NUM_LINKS=$(stat -c %h $1)
. Zobacz man stat
więcej zmiennych formatu, których możesz użyć.
ls -l
Pierwsza kolumna będzie reprezentować uprawnienia. Druga kolumna będzie liczbą podelementów (dla katalogów) lub liczbą ścieżek do tych samych danych (twarde linki, w tym oryginalny plik) do pliku. Na przykład:
-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
^ Number of hard links to the data
inode
co z kolei wskazuje na zawartość dysku.
Co powiesz na następującą prostszą? (Później może zastąpić powyższe długie skrypty!)
Jeśli masz konkretny plik <THEFILENAME>
i chcesz poznać wszystkie jego łącza twarde rozproszone po katalogu <TARGETDIR>
, (może to być nawet cały system plików oznaczony przez /
)
find <TARGETDIR> -type f -samefile <THEFILENAME>
Rozszerzając logikę, jeśli chcesz poznać wszystkie pliki, <SOURCEDIR>
które mają wiele rozpiętych linków <TARGETDIR>
:
find <SOURCEDIR> -type f -links +1 \
-printf "\n\n %n HardLinks of file : %H/%f \n" \
-exec find <TARGETDIR> -type f -samefile {} \;
-type f
ponieważ plik może być również katalogiem.
.
I ..
wpisy w katalogach są hardlinki. Możesz dowiedzieć się, ile podkatalogów znajduje się w katalogu na podstawie liczby linków .
. To i tak jest dyskusyjne, ponieważ find -samefile .
nadal nie wydrukuje żadnych subdir/..
wyników. find
(przynajmniej wersja GNU) wydaje się być zakodowana na stałe ..
, nawet z -noleaf
.
O(n^2)
i działa find
raz dla każdego członka zestawu plików dowiązanych na stałe. find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
działałby (16 nie jest wystarczająco szeroki, aby dziesiętna reprezentacja 2 ^ 63-1, więc gdy twój system plików XFS jest wystarczająco duży, aby mieć tak wysokie liczby i-węzłów, uważaj)
Istnieje wiele odpowiedzi ze skryptami, aby znaleźć wszystkie dowiązania twarde w systemie plików. Większość z nich robi takie głupie rzeczy, jak uruchamianie funkcji wyszukiwania, aby skanować cały system plików w -samefile
poszukiwaniu KAŻDEGO pliku z wieloma linkami. To jest szalone; wystarczy posortować według numeru i-węzła i wydrukować duplikaty.
Za pomocą jednego przejścia przez system plików można znaleźć i zgrupować wszystkie zestawy plików dowiązanych na stałe
find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
sort -n | uniq -w 42 --all-repeated=separate
Jest to znacznie szybsze niż inne odpowiedzi na znalezienie wielu zestawów plików dowiązanych na stałe.
find /foo -samefile /bar
jest doskonały tylko dla jednego pliku.
-xdev
: ograniczenie do jednego systemu plików. Nie jest to absolutnie potrzebne, ponieważ drukujemy również FS-id na uniq! -type d
odrzuć katalogi: wpisy .
i ..
oznaczają, że zawsze są połączone.-links +1
: liczba linków ściśle > 1
-printf ...
wypisz FS-id, numer i-węzła i ścieżkę. (Z dopełnieniem do ustalonych szerokości kolumn, o których możemy powiedzieć uniq
.)sort -n | uniq ...
sortuj numerycznie i unikaj pierwszych 42 kolumn, oddzielając grupy pustą liniąUżycie ! -type d -links +1
oznacza, że dane wejściowe sort są tak duże, jak końcowy wynik uniq, więc nie wykonujemy dużej ilości sortowania łańcuchów. Chyba że uruchomisz go w podkatalogu, który zawiera tylko jeden z zestawu dowiązań twardych. W każdym razie spowoduje to o wiele krótszy czas pracy procesora przez system plików niż w przypadku innych opublikowanych rozwiązań.
próbka wyjściowa:
...
2429 76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
2429 76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar
2430 17961006 /usr/bin/pkg-config.real
2430 17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config
2430 36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
2430 36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...
TODO ?: rozpakuj wyjście za pomocą awk
lub cut
. uniq
ma bardzo ograniczone wsparcie wyboru pola, więc wpisuję wyniki wyszukiwania i używam stałej szerokości. 20 znaków jest wystarczająco szeroki, aby pomieścić maksymalny możliwy numer i-węzła lub urządzenia (2 ^ 64-1 = 18446744073709551615). XFS wybiera numery i-węzłów na podstawie miejsca, w którym są przydzielane na dysku, a nie od 0, więc duże systemy plików XFS mogą mieć> i-bitowe liczby i-węzłów, nawet jeśli nie mają miliardów plików. Inne systemy plików mogą mieć 20-cyfrowe numery i-węzłów, nawet jeśli nie są gigantyczne.
DO ZROBIENIA: posortuj grupy duplikatów według ścieżki. Posortowanie ich według punktu montowania, a następnie liczba i-węzłów miesza rzeczy razem, jeśli masz kilka różnych podkatalogów, które mają wiele dowiązań twardych. (tzn. grupy dup-grup idą w parze, ale wynik miesza je).
Finał sort -k 3
sortowałby linie osobno, a nie grupy linii jako pojedynczy rekord. Przetwarzanie wstępne z czymś, co przekształca parę znaków nowej linii w bajt NUL, i użycie GNU sort --zero-terminated -k 3
może załatwić sprawę. tr
działa tylko na pojedyncze znaki, a nie na 2-> 1 lub 1-> 2 wzorce. perl
zrobiłbym to (lub po prostu parsował i sortował w perl lub awk). sed
może również działać.
%D
to identyfikator systemu plików (jest unikalny dla bieżącego rozruchu, gdy żadne systemy plików są umount
ed), więc po jest jeszcze bardziej ogólna: find directories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' | sort -n | uniq -w 42 --all-repeated=separate
. Działa to tak długo, jak długo dany katalog nie zawiera innego katalogu na poziomie systemu plików, a także sprawdza wszystko, co może być dowiązane na twardo (jak urządzenia lub softlink - tak, softlink może mieć liczbę linków większą niż 1). Należy pamiętać, że dev_t
i ino_t
ma długość 64 bitów dzisiaj. Prawdopodobnie będzie tak długo, dopóki będziemy mieli 64-bitowe systemy.
! -type d
zamiast -type f
. Mam nawet pewne dowiązania symboliczne w moim systemie plików z organizacji niektórych zbiorów plików. Zaktualizowałem moją odpowiedź o ulepszoną wersję (ale najpierw umieściłem fs-id, więc sortuj co najmniej grupy według systemu plików.)
Jest to nieco komentarz do własnej odpowiedzi i skryptu Torocoro-Macho, ale oczywiście nie mieści się w polu komentarza.
Przepisz swój skrypt w prostszy sposób, aby znaleźć informacje, a tym samym znacznie mniej wywołań procesów.
#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
[ -d "${xFILE}" ] && continue
[ ! -r "${xFILE}" ] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
nLINKS=$(stat -c%h "${xFILE}")
if [ ${nLINKS} -gt 1 ]; then
iNODE=$(stat -c%i "${xFILE}")
xDEVICE=$(stat -c%m "${xFILE}")
printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -printf ' -> %p\n' 2>/dev/null
fi
done
Starałem się zachować jak najbardziej podobny do twojego, aby ułatwić porównanie.
Zawsze należy unikać $IFS
magii, jeśli glob jest wystarczający, ponieważ jest niepotrzebnie zawinięty, a nazwy plików mogą faktycznie zawierać znaki nowej linii (ale w praktyce głównie pierwszy powód).
Powinieneś unikać ręcznego parsowania ls
i takich danych wyjściowych, jak to możliwe, ponieważ prędzej czy później cię ugryzie. Na przykład: w pierwszym awk
wierszu nie powiodły się wszystkie nazwy plików zawierające spacje.
printf
często oszczędza kłopotów, ponieważ jest tak odporny na %s
składnię. Daje także pełną kontrolę nad wyjściem i jest spójny we wszystkich systemach, w przeciwieństwie do echo
.
stat
może zaoszczędzić ci dużo logiki w tym przypadku.
GNU find
jest potężny.
Twoje head
i tail
wywołania mogły być obsługiwane bezpośrednio za awk
pomocą np. exit
Polecenia i / lub wyboru NR
zmiennej. Pozwoliłoby to zaoszczędzić wywołania procesów, które prawie zawsze znacznie poprawiają wydajność w ciężko pracujących skryptach.
Twoje egrep
równie dobrze mogą być sprawiedliwe grep
.
find ... -xdev -type f -links +1 -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
. Jest O DUŻO szybszy, ponieważ przemierza fs tylko raz. W przypadku wielu FS na raz, numery i-węzłów muszą być poprzedzone identyfikatorem FS. Może zfind -exec stat... -printf ...
Opierając się na findhardlinks
skrypcie (przemianowanym na hard-links
), właśnie to zreformowałem i sprawiłem, że działa.
Wynik:
# ./hard-links /root
Item: /[10145] = /root/.profile
-> /proc/907/sched
-> /<some-where>/.profile
Item: /[10144] = /root/.tested
-> /proc/907/limits
-> /<some-where else>/.bashrc
-> /root/.testlnk
Item: /[10144] = /root/.testlnk
-> /proc/907/limits
-> /<another-place else>/.bashrc
-> /root/.tested
# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
xITEM="${xPATH}/${xFILE}";
if [[ ! -r "${xITEM}" ]] ; then
echo "Path: '${xITEM}' is not accessible! ";
else
nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
if [ ${nLINKS} -gt 1 ]; then
iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/ -> /';
fi
fi
done
IFS="${oIFS}"; echo "";
Rozwiązanie GUI bardzo zbliża się do twojego pytania:
Nie można wyświetlić rzeczywistych plików dowiązań z „ls”, ponieważ, jak zauważyli poprzedni komentatorzy, „nazwy” plików są jedynie aliasami do tych samych danych. Jednak tak naprawdę istnieje narzędzie GUI, które naprawdę zbliża się do tego, czego chcesz, czyli wyświetlanie listy ścieżek nazw plików, które wskazują na te same dane (jako twarde linki) w systemie Linux, nazywa się FSLint. Opcja, którą chcesz znaleźć, znajduje się w „Zderzenia nazw” -> odznacz „pole wyboru $ ŚCIEŻKA” w Wyszukiwarce (XX) -> i wybierz „Aliasy” z rozwijanego menu po „dla ...” w kierunku górnej środkowej części.
FSLint jest bardzo słabo udokumentowany, ale stwierdziłem, że upewniłem się, że drzewo katalogu jest ograniczone pod „Ścieżką wyszukiwania” z zaznaczonym polem wyboru „Recurse?” oraz wyżej wspomniane opcje, lista danych połączonych na stałe ze ścieżkami i nazwami, które „wskazują” na te same dane, są tworzone po wyszukiwaniu programu.
Możesz skonfigurować ls
podświetlanie linków twardych za pomocą „aliasu”, ale jak wspomniano wcześniej, nie ma sposobu, aby pokazać „źródło” linku twardego, dlatego dołączam .hardlink
do pomocy.
Dodaj następujące gdzieś w swoim .bashrc
alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
link(2)
wywołaniu systemowym nie ma sensu, który z nich jest oryginalny, a drugi link. Dlatego, jak wskazują odpowiedzi, jedynym sposobem na znalezienie wszystkich linków jestfind / -samefile /a/A
. Ponieważ jeden wpis katalogu dla i-węzła nie „wie” o innych wpisach katalogu dla tego samego i-węzła. Wszystko, co robią, to ponownie liczą i-węzeł, aby można go było usunąć, gdy jest to jego nazwiskounlink(2)ed
. (Jest to „liczba linków” nals
wyjściu).