Wie können Sie den tatsächlichen harten Link mit ls sehen?
Ich führe
ln /a/A /b/B
aus und möchte im Ordner a
sehen, worauf die Datei A mit ls
zeigt.
Ich führe
ln /a/A /b/B
aus und möchte im Ordner a
sehen, worauf die Datei A mit ls
zeigt.
Sie können die Inode-Nummer für Ihre Datei mit
ls -i
finden und
ls -l
zeigt die Anzahl der Referenzen (Anzahl der Hardlinks zu einem bestimmten Inode)
nachdem Sie die Inode-Nummer gefunden haben, können Sie nach allen Dateien mit demselben Inode suchen:
find . -inum NUM
zeigt die Dateinamen für Inode NUM im aktuellen Verzeichnis (.)
Es gibt nicht wirklich eine eindeutige Antwort auf Ihre Frage. Im Gegensatz zu Symlinks sind Hardlinks nicht von der “Originaldatei” zu unterscheiden.
Verzeichniseinträge bestehen aus einem Dateinamen und einem Zeiger auf einen Inode. Der Inode wiederum enthält die Datei-Metadaten und (Zeiger auf) den eigentlichen Dateiinhalt). Das Erstellen eines Hardlinks erzeugt einen weiteren Dateinamen + Verweis auf denselben Inode. Diese Referenzen sind unidirektional (zumindest in typischen Dateisystemen) - die Inode führt nur einen Referenzzähler. Es gibt keine Möglichkeit, herauszufinden, welches der “ursprüngliche” Dateiname ist.
Das ist übrigens der Grund, warum der Systemaufruf zum “Löschen” einer Datei unlink
heißt. Er entfernt nur einen Hardlink. Die Inode und die angehängten Daten werden nur gelöscht, wenn die Anzahl der Verweise auf die Inode auf 0 sinkt.
Die einzige Möglichkeit, die anderen Verweise auf eine bestimmte Inode zu finden, besteht darin, das Dateisystem erschöpfend zu durchsuchen und zu prüfen, welche Dateien auf die betreffende Inode verweisen. Sie können ‘test A -ef B’ von der Shell aus verwenden, um diese Prüfung durchzuführen.
ls -l
Die erste Spalte stellt die Berechtigungen dar. Die zweite Spalte wird die Anzahl der Unterpunkte (bei Verzeichnissen) oder die Anzahl der Pfade zu den gleichen Daten (Hardlinks, einschließlich der Originaldatei) zur Datei sein. Beispiel:
-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
^ Number of hard links to the data
Wie wäre es mit der folgenden, einfacheren Variante? (Letzteres könnte die langen Skripte oben ersetzen!)
Wenn Sie eine bestimmte Datei <THEFILENAME>
haben und alle ihre Hardlinks über das Verzeichnis <TARGETDIR>
verteilt wissen wollen (was sogar das gesamte Dateisystem sein kann, das durch /
bezeichnet wird),
find <TARGETDIR> -type f -samefile <THEFILENAME>
Erweitern Sie die Logik, wenn Sie alle Dateien im Verzeichnis <SOURCEDIR>
mit mehreren Hardlinks über <TARGETDIR>
verteilt wissen wollen:
find <SOURCEDIR> -type f -links +1 \
-printf "\n\n %n HardLinks of file : %H/%f \n" \
-exec find <TARGETDIR> -type f -samefile {} \;
Es gibt eine Menge Antworten mit Skripten, um alle Hardlinks in einem Dateisystem zu finden. Die meisten von ihnen machen dumme Sachen, wie z. B. find laufen zu lassen, um das gesamte Dateisystem nach -samefile
für JEDE mehrfach verknüpfte Datei zu scannen. Das ist verrückt; alles, was Sie brauchen, ist eine Sortierung nach Inode-Nummer und die Ausgabe von Duplikaten.
Mit nur einem Durchlauf durch das Dateisystem, um alle Sätze von hartverknüpften Dateien zu finden und zu gruppieren
find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
sort -n | uniq -w 42 --all-repeated=separate
Dies ist viel schneller als die anderen Antworten, um mehrere Sätze von hartverknüpften Dateien zu finden.
find /foo -samefile /bar
ist hervorragend für nur eine Datei.
-xdev
: Begrenzung auf ein Dateisystem. Nicht unbedingt nötig, da wir die FS-id auch bei ! -type d
Verzeichnissen an uniq ausgeben: die .
und ..
Einträge bedeuten, dass sie immer verlinkt sind. -links +1
: Link-Zählung streng > 1
-printf ...
drucken FS-id, Inode-Nummer und Pfad. (Mit Auffüllen auf feste Spaltenbreiten, die wir uniq
mitteilen können.) sort -n | uniq ...
numerisches Sortieren und Eindeutigmachen auf den ersten 42 Spalten, Trennen von Gruppen mit einer Leerzeile Die Verwendung von ! -type d -links +1
bedeutet, dass die Eingabe von sort nur so groß ist wie die endgültige Ausgabe von uniq, so dass wir keine große Menge an Stringsortierung durchführen. Es sei denn, Sie lassen es auf einem Unterverzeichnis laufen, das nur einen aus einer Reihe von Hardlinks enthält. Wie auch immer, dies verbraucht VIEL weniger CPU-Zeit beim Durchlaufen des Dateisystems als jede andere gepostete Lösung.
Beispiel-Ausgabe:
...
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?: Entpacken Sie die Ausgabe mit awk
oder cut
. uniq
hat eine sehr eingeschränkte Feldauswahlunterstützung, daher fülle ich die Suchausgabe auf und verwende eine feste Breite. 20Zeichen ist breit genug für die maximal mögliche Inode- oder Gerätenummer (2^64-1 = 18446744073709551615). XFS wählt Inode-Nummern basierend darauf, wo auf der Platte sie zugewiesen werden, nicht zusammenhängend von 0 an, so dass große XFS-Dateisysteme >32-Bit-Inode-Nummern haben können, auch wenn sie nicht Milliarden von Dateien haben. Andere Dateisysteme können 20-stellige Inode-Nummern haben, auch wenn sie nicht gigantisch sind.
TODO: Gruppen von Duplikaten nach Pfad sortieren. Sie nach Einhängepunkt und dann nach Inode-Nummer sortiert zu haben, bringt die Dinge durcheinander, wenn Sie ein paar verschiedene Unterverzeichnisse haben, die viele Hardlinks haben. (d.h. Gruppen von Dup-Gruppen gehören zusammen, aber die Ausgabe mischt sie durcheinander).
Ein abschließendes sort -k 3
würde Zeilen separat sortieren, nicht Gruppen von Zeilen als einen einzigen Datensatz. Eine Vorverarbeitung mit etwas, um ein Paar Zeilenumbrüche in ein NUL-Byte umzuwandeln, und die Verwendung von GNU sort --zero-terminated -k 3
könnte den Zweck erfüllen. tr
arbeitet allerdings nur mit einzelnen Zeichen, nicht mit 2>1 oder 1>2 Mustern. perl
würde es tun (oder einfach parsen und sortieren in perl oder awk). sed
könnte auch funktionieren.
Dies ist eine Art Kommentar zu Torocoro-Machos eigener Antwort und Skript, aber es passt offensichtlich nicht in das Kommentarfeld._
Ich habe Ihr Skript umgeschrieben, mit einfacheren Möglichkeiten, die Informationen zu finden, und daher viel weniger Prozessaufrufen.
#!/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
Ich habe versucht, es Ihrem so ähnlich wie möglich zu halten, um einen einfachen Vergleich zu ermöglichen.
Man sollte die $IFS
-Magie immer vermeiden, wenn ein glob ausreicht, da sie unnötig umständlich ist, und Dateinamen tatsächlich Zeilenumbrüche enthalten können (in der Praxis aber meist der erste Grund).
Sie sollten das manuelle Parsen von ls
und solchen Ausgaben so weit wie möglich vermeiden, da es Sie früher oder später beißen wird. Zum Beispiel: in Ihrer ersten awk
-Zeile scheitern Sie an allen Dateinamen, die Leerzeichen enthalten.
printf
wird Ihnen am Ende oft Ärger ersparen, da es mit der %s
-Syntax so robust ist. Es gibt Ihnen außerdem die volle Kontrolle über die Ausgabe und ist im Gegensatz zu echo
auf allen Systemen konsistent.
stat
kann Ihnen in diesem Fall eine Menge Logik ersparen.
GNU find
ist leistungsstark.
Ihre head
- und tail
-Aufrufe hätten direkt in awk
behandelt werden können, z. B. mit dem Befehl exit
und/oder der Auswahl auf der NR
-Variablen. Das würde Prozessaufrufe einsparen, was in hart arbeitenden Skripten fast immer die Performance stark verbessert.
Ihre egrep
s könnten genauso gut einfach grep
sein.
Basierend auf dem Skript findhardlinks
(umbenannt in hard-links
) habe ich das folgende Skript umstrukturiert, damit es funktioniert.
Ausgabe:
# ./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 "";
Eine GUI-Lösung kommt Ihrer Frage sehr nahe:
Sie können die tatsächlichen Hardlinks von “ls” nicht auflisten, weil die Datei-“Namen”, wie schon von anderen Kommentatoren erwähnt, nur Aliase auf dieselben Daten sind. Es gibt aber tatsächlich ein GUI-Tool, das dem, was Sie wollen, sehr nahe kommt, nämlich eine Pfadauflistung von Dateinamen, die auf dieselben Daten (als Hardlinks) zeigen, unter Linux anzuzeigen, es heißt FSLint. Die gewünschte Option finden Sie unter “Namenskonflikte” -> deaktivieren Sie “checkbox $PATH” in Search (XX) -> und wählen Sie “Aliases” aus der Dropdown-Box nach “for…” in der oberen Mitte.
FSLint ist sehr schlecht dokumentiert, aber ich habe herausgefunden, dass das Sicherstellen des eingeschränkten Verzeichnisbaums unter “Suchpfad” mit der aktivierten Checkbox für “Recurse?” und den oben genannten Optionen, eine Auflistung von fest verknüpften Daten mit Pfaden und Namen, die auf die gleichen Daten “zeigen”, erzeugt, nachdem das Programm sucht.
Sie können ls
so konfigurieren, dass Hardlinks mit einem “Alias” hervorgehoben werden, aber wie bereits erwähnt, gibt es keine Möglichkeit, die “Quelle” des Hardlinks anzuzeigen, weshalb ich .hardlink
anhänge, um dabei zu helfen.
Fügen Sie das Folgende irgendwo in Ihrem .bashrc
alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
``` hinzu