Wie können Sie die tatsächliche harte Verbindung von ls sehen?

135868
Léo Léopold Hertz 준영

ich renne

ln /a/A /b/B 

Ich möchte in dem Ordner sehen, awo die Datei A zeigt ls.

82
Hardlinks sind keine Zeiger, Symlinks sind. Sie sind mehrere Namen für dieselbe Datei (Inode). Nach einem Systemaufruf von 'link (2)' hat es keinen Sinn, bei welchem ​​das Original das Original und das Link der Link ist. Wie die Antworten zeigen, ist der einzige Weg, alle Links zu finden, `find / -samefile / a / A`. Weil ein Verzeichniseintrag für einen Inode keine anderen Verzeichniseinträge für denselben Inode "kennt". Sie müssen lediglich den Inode neu zählen, so dass er gelöscht werden kann, wenn der letzte Name "Unlink (2) ed" ist. (Dies ist die "Link-Anzahl" in der Ausgabe von "ls"). Peter Cordes vor 9 Jahren 0
@ PeterCordes: Ist der Refcount tatsächlich im Hardlink-Eintrag gespeichert? Das ist, was Ihre Formulierung impliziert ("Alles, was sie tun, ist, den Inode neu zu zählen ..."). Aber das würde keinen Sinn machen, wenn die Links nichts voneinander wissen, denn wenn einer aktualisiert wird, müssten alle anderen irgendwie bleibe auf dem Laufenden. Oder ist der Refcount im Inode selbst gespeichert? (Vergib mir, wenn es eine dumme Frage ist, ich betrachte mich als Neuling und lerne immer noch). loneboat vor 8 Jahren 0
Der Refcount wird im Inode gespeichert, wie Sie schließlich anhand der anderen Fakten feststellen mussten. :) Verzeichniseinträge sind benannte Zeiger auf Inodes. Wir nennen es "Hard Linking", wenn Sie mehrere Namen auf den gleichen Inode haben. Peter Cordes vor 8 Jahren 0

10 Antworten auf die Frage

150
zzr

Sie finden die Inode-Nummer für Ihre Datei mit

ls -i 

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 Dateinamen für Inode NUM im aktuellen Verzeichnis an (.)

du könntest einfach laufen finden. -samefile Dateiname BeowulfNode42 vor 10 Jahren 42
@ BeowulfNode42 Dieser Befehl ist großartig, aber er benötigt mindestens den freigegebenen Stammordner der gleichen Dateien. Itachi vor 7 Jahren 1
Diese Antwort gibt ein pragmatisches "do this", aber ich glaube stark, dass [@LaurenceGonsalves antwortet] (http://superuser.com/a/12973/28756) die "wie" und / oder "warum" -Fragen. Trevor Boyd Smith vor 7 Jahren 1
55
Laurence Gonsalves

Es gibt keine genau definierte Antwort auf Ihre Frage. Hardlinks sind im Gegensatz zu Symlinks nicht von der "Originaldatei" zu unterscheiden.

Verzeichniseinträge bestehen aus einem Dateinamen und einem Zeiger auf einen Inode. Der Inode enthält wiederum die Dateimetadaten und (Zeiger auf) den tatsächlichen Dateiinhalt. Durch das Erstellen eines festen Links wird ein weiterer Dateiname + Verweis auf denselben Inode erstellt. Diese Referenzen sind unidirektional (zumindest in typischen Dateisystemen) - der Inode führt nur eine Referenzzählung. Es gibt keine intrinsische Methode, um herauszufinden, welcher Dateiname "Original" ist.

Aus diesem Grund wird der Systemaufruf zum "Löschen" einer Datei aufgerufen unlink. Es wird nur ein Hardlink entfernt. Die angehängten Daten eines Inodes werden nur gelöscht, wenn der Referenzzähler des Inodes auf 0 fällt.

Die anderen Verweise auf einen bestimmten Inode können Sie nur finden, indem Sie das Dateisystem gründlich durchsuchen und prüfen, welche Dateien auf den betreffenden Inode verweisen. Sie können 'test A -ef B' aus der Shell verwenden, um diese Prüfung durchzuführen.

Das bedeutet, dass es * keine harte Verbindung zu einer anderen Datei * gibt, da die Originaldatei auch eine harte Verbindung ist. Hardlinks verweisen auf eine * Position auf der Festplatte *. jtbandes vor 14 Jahren 30
@jtbandes: Harte Links zeigen auf einen Inode, der auf die tatsächlichen Daten zeigt. dash17291 vor 10 Jahren 9
32

UNIX hat harte Links und symbolische Links (hergestellt mit "ln"und "ln -s"jeweils). Symbolische Links sind einfach eine Datei, die den tatsächlichen Pfad zu einer anderen Datei enthält und Dateisysteme überschreiten kann.

Harte Links gibt es seit den ersten Tagen von UNIX (an die ich mich sowieso erinnern kann, und das geht schon eine Weile zurück). Es handelt sich um zwei Verzeichniseinträge, die auf genau die gleichen zugrunde liegenden Daten verweisen . Die Daten in einer Datei werden durch ihre angegeben inode. Jede Datei in einem Dateisystem verweist auf einen Inode, aber es ist nicht erforderlich, dass jede Datei auf einen eindeutigen Inode verweist - da kommen harte Links zustande.

Da Inodes nur für ein bestimmtes Dateisystem eindeutig sind, gibt es eine Einschränkung, dass sich feste Links auf demselben Dateisystem befinden müssen (im Gegensatz zu symbolischen Links). Beachten Sie, dass es im Gegensatz zu symbolischen Links keine privilegierten Dateien gibt - sie sind alle gleich. Der Datenbereich wird nur freigegeben, wenn alle Dateien, die diesen Inode verwenden, gelöscht werden (und alle Prozesse ihn ebenfalls schließen, dies ist jedoch ein anderes Problem).

Sie können den "ls -i"Befehl verwenden, um den Inode einer bestimmten Datei abzurufen. Sie können dann den "find <filesystemroot> -inum <inode>"Befehl verwenden, um alle Dateien im Dateisystem mit dem angegebenen Inode zu finden.

Hier ist ein Skript, das genau das tut. Sie rufen es an mit:

findhardlinks ~/jquery.js 

und es werden alle Dateien in diesem Dateisystem gefunden, die feste Links für diese Datei sind:

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 

Hier ist das Skript.

#!/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 '') inode=$(ls -id "$1" | awk '' | head -1l) device=$(df "$1" | tail -1l | awk '') echo " '$1' has inode $ on mount point '$'" find $ -inum $ 2>/dev/null | sed 's/^/ /' fi shift done 
@pax: Es scheint einen Fehler im Skript zu geben. Ich beginne mit `. . / findhardlinks.bash`, während Sie sich in OS Xs Zsh befinden. Mein aktuelles Fenster im Bildschirm wird geschlossen. vor 14 Jahren 0
@Masi Das Problem ist deine Initiale. (wie beim Quellbefehl). Dadurch verlässt der Befehl exit 1 Ihre Shell. Verwenden Sie chmod a + x findhardlinks.bash und führen Sie es mit ./findhardlinks.bash aus oder verwenden Sie bash findhardlinks.bash njsf vor 14 Jahren 3
Bitte sehen Sie meine Antwort auf Ihre Antwort unter http://superuser.com/questions/12972/to-see-hardlinks-by-ls/13233#13233 Léo Léopold Hertz 준영 vor 14 Jahren 0
Um dies programmgesteuert durchzuführen, ist es wahrscheinlich widerstandsfähiger, wenn Sie stattdessen Folgendes verwenden: `INUM = $ (stat -c% i $ 1)`. Auch `NUM_LINKS = $ (stat -c% h $ 1)`. Weitere Formatvariablen, die Sie verwenden können, finden Sie unter "man stat". Joe vor 12 Jahren 1
Beste Antwort, bei weitem. Kudos MariusMatutiae vor 8 Jahren 0
Ja, tolle Erklärung mit der richtigen Antwort :) sMyles vor 6 Jahren 0
24
eyelidlessness
ls -l 

Die erste Spalte enthält Berechtigungen. Die zweite Spalte enthält die Anzahl der Unterelemente (für Verzeichnisse) oder die Anzahl der Pfade zu denselben Daten (feste Links einschließlich der Originaldatei) zur Datei. Z.B:

-rw-r--r--@ 2 [username] [group] [timestamp] HardLink -rw-r--r--@ 2 [username] [group] [timestamp] Original ^ Number of hard links to the data 
Hilfreich bei der Feststellung, ob eine bestimmte Datei [andere] feste Links hat, aber nicht, wo sie sich befinden. mklement0 vor 9 Jahren 2
9
Loves Probability

Wie wäre es mit dem folgenden einfacheren? (Letzteres könnte die langen Skripts oben ersetzen!)

Wenn Sie eine bestimmte Datei haben <THEFILENAME>und wissen möchten, dass alle ihre Hardlinks über das Verzeichnis verteilt <TARGETDIR>sind (dies kann sogar das gesamte Dateisystem sein, das mit bezeichnet ist /)

find <TARGETDIR> -type f -samefile <THEFILENAME> 

Erweitern Sie die Logik, wenn Sie wissen möchten, dass alle Dateien <SOURCEDIR>über mehrere feste Links verteilt sind <TARGETDIR>:

find <SOURCEDIR> -type f -links +1 \ -printf "\n\n %n HardLinks of file : %H/%f \n" \ -exec find <TARGETDIR> -type f -samefile {} \;  
Das ist für mich die beste Antwort! aber ich würde nicht `-type f` verwenden, da die Datei auch ein Verzeichnis sein kann. silvio vor 10 Jahren 0
@silvio: Sie können nur feste Links zu _files_ erstellen, nicht zu Verzeichnissen. mklement0 vor 9 Jahren 2
@ mklement0: Du hast recht! silvio vor 9 Jahren 0
Die Einträge `.` und` ..` in Verzeichnissen sind Hardlinks. Wie viele Unterverzeichnisse sich in einem Verzeichnis befinden, können Sie der Link-Anzahl von `.` entnehmen. Dies ist ohnehin umstritten, da `find -samefile.` Noch keine Ausgabe von `subdir / ..` druckt. `find` (zumindest die GNU-Version) scheint hart zu codieren, um` ..` selbst mit `-noleaf` zu ignorieren. Peter Cordes vor 9 Jahren 0
Diese find-all-links-Idee ist ebenfalls "O (n ^ 2)" und führt "find" einmal für jedes Mitglied einer Gruppe von fest verknüpften Dateien aus. `find ... -printf '% 16i% p \ n' | sort -n | uniq -w 16 --all-repeat = separate` würde funktionieren (16 ist nicht breit genug für eine dezimale Darstellung von 2 ^ 63-1). Wenn Ihr XFS-Dateisystem groß genug ist, um Inode-Nummern mit so hohen Werten zu haben, sollten Sie aufpassen ) Peter Cordes vor 9 Jahren 0
verwandelte das in eine Antwort Peter Cordes vor 9 Jahren 0
4
Peter Cordes

Es gibt viele Antworten mit Skripten, um alle Hardlinks in einem Dateisystem zu finden. Die meisten von ihnen machen dumme Sachen, wie das Ausführen von find, um das gesamte Dateisystem -samefilenach JEDER mit mehreren verknüpften Dateien zu durchsuchen. Das ist verrückt; Sie müssen lediglich nach Inode-Nummern sortieren und Duplikate drucken.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Danke an @Tino für die Optimierung meines ursprünglichen Befehls, um eine FS-id ( %D) zu unterstützen, und um alle Nicht-Verzeichnis-Dateitypen zu behandeln, nicht nur reguläre Dateien. Dadurch werden Ihre mehrfach verknüpften Symlinks, Pipes usw. gefunden.)

Das ! -type d -links +1bedeutet, dass die Eingabe von sort nur so groß ist wie die endgültige Ausgabe von uniq. Es sei denn, Sie führen es in einem Unterverzeichnis aus, das nur einen Satz von Hardlinks enthält. Auf jeden Fall wird dadurch eine viel weniger CPU-Zeit benötigt, die das Dateisystem erneut durchläuft als jede andere veröffentlichte Lösung.

Beispielausgabe:

... 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 ?: Aufheben der Ausgabe. uniqhat eine sehr begrenzte Unterstützung für die Feldauswahl, daher füge ich die Suchausgabe auf und verwende eine feste Breite. 20 Zeichen ist breit genug für die maximal mögliche Inode- oder Gerätenummer (2 ^ 64-1 = 18446744073709551615). XFS wählt Inode-Nummern basierend auf dem zugewiesenen Speicherplatz auf der Festplatte, nicht zusammenhängend von 0, sodass große XFS-Dateisysteme> 32-Bit-Inode-Nummern haben können, auch wenn sie keine Milliarden von Dateien haben. Andere Dateisysteme haben möglicherweise 20-stellige Inode-Nummern, auch wenn sie nicht gigantisch sind.

TODO: Sortiert Gruppen von Duplikaten nach Pfad. Wenn sie nach Mount-Punkt sortiert sind, mischt die Inode-Nummer die Dinge zusammen, wenn Sie mehrere Subdirs haben, die viele Hardlinks enthalten. (dh Gruppen von Dup-Gruppen gehören zusammen, aber die Ausgabe mischt sie zusammen).

Ein Finale sort -k 3würde Zeilen separat sortieren, nicht Zeilengruppen als einzelnen Datensatz. Vorverarbeitung mit etwas, um ein Paar Zeilenumbrüche in ein NUL-Byte zu verwandeln, und die Verwendung von GNU sort --zero-terminated -k 3könnte den Trick erfüllen . trFunktioniert nur für einzelne Zeichen, jedoch nicht für Muster mit 2> 1 oder 1> 2. perlwürde es tun (oder einfach nur perl oder awk parsen und sortieren). sedkönnte auch funktionieren.

% D ist die Kennung des Dateisystems (es ist eindeutig für den aktuellen Start, während keine Dateisysteme umount sind), daher wird noch generischer: `find Directories .. -xdev! -typ d -links +1 -printf '% 20i% 20D% p \ n' | sort -n | uniq -w 42 - alle wiederholt = getrennt ". Dies funktioniert, solange in keinem der angegebenen Verzeichnisse ein anderes Verzeichnis auf Dateisystemebene vorhanden ist. Außerdem wird alles durchsucht, was mit einem Hardlink verknüpft werden kann (z. B. Geräte oder Softlinks. Ja, Softlinks können eine Linkanzahl von mehr als 1 haben). Beachten Sie, dass "dev_t" und "ino_t" heute 64 Bit lang sind. Dies wird wahrscheinlich so lange gelten, wie wir 64-Bit-Systeme haben. Tino vor 8 Jahren 1
@Tino: Toller Punkt zur Verwendung von `! -type d` anstelle von `-type f`. Ich habe sogar einige Hardlink-Symlinks in meinem Dateisystem, wenn ich einige Sammlungen von Dateien organisiere. Meine Antwort wurde mit Ihrer verbesserten Version aktualisiert (aber ich stelle zuerst die fs-id ein, daher sortiert die Sortierreihenfolge zumindest nach Dateisystem.) Peter Cordes vor 8 Jahren 0
3
Daniel Andersson

This is somewhat of a comment to Torocoro-Macho's own answer and script, but it obviously won't fit in the comment box.


Rewrote your script with more straightforward ways to find the info, and thus a lot less process invocations.

#!/bin/sh xPATH=$(readlink -f -- "$") for xFILE in "$"/*; do [ -d "$" ] && continue [ ! -r "$" ] && printf '"%s" is not readable.\n' "$" 1>&2 && continue nLINKS=$(stat -c%h "$") if [ $ -gt 1 ]; then iNODE=$(stat -c%i "$") xDEVICE=$(stat -c%m "$") printf '\nItem: %s[%d] = %s\n' "$" "$" "$"; find "$" -inum $ -not -path "$" -printf ' -> %p\n' 2>/dev/null fi done 

I tried to keep it as similar to yours as possible for easy comparison.

Comments on this script and yours

  • One should always avoid the $IFS magic if a glob suffices, since it is unnecessarily convoluted, and file names actually can contain newlines (but in practice mostly the first reason).

  • You should avoid manually parsing ls and such output as much as possible, since it will sooner or later bite you. For example: in your first awk line, you fail on all file names containing spaces.

  • printf will often save troubles in the end since it is so robust with the %s syntax. It also gives you full control over the output, and is consistent across all systems, unlike echo.

  • stat can save you a lot of logic in this case.

  • GNU find is powerful.

  • Your head and tail invocations could have been handled directly in awk with e.g. the exit command and/or selecting on the NR variable. This would save process invocations, which almost always betters performance severely in hard-working scripts.

  • Your egreps could just as well be just grep.

xDEVICE = $ (stat -c% m "$ ") funktioniert nicht auf allen Systemen (z. B. stat (GNU coreutils) 6.12). Wenn das Skript "Item:?" Ersetzen Sie diese Zeile am Anfang jeder Zeile durch eine Zeile, die dem ursprünglichen Skript ähnelt, jedoch mit xITEM in xFILE umbenannt wird: xDEVICE = $ (df "$ " | tail -1l | awk ' ') kbulgrien vor 10 Jahren 0
Wenn Sie nur Gruppen von Hardlinks wünschen, anstatt sie mit jedem Mitglied als "Master" zu wiederholen, verwenden Sie "find ... -xdev -type f -links +1 -printf"% 16i% p \ n '| sort -n | uniq -w 16 - alle wiederholt = einzeln ". Dies ist VIEL schneller, da es die fs nur einmal durchquert. Für mehrere FS auf einmal müssen Sie den Inode-Nummern eine FS-ID voranstellen. Vielleicht mit `find -exec stat ... -printf ...` Peter Cordes vor 9 Jahren 0
verwandelte diese Idee in eine Antwort Peter Cordes vor 9 Jahren 0
2
Torocoro-Macho

Basierend auf dem findhardlinksSkript (umbenannt in hard-links), habe ich dies überarbeitet und zum Laufen gebracht.

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=$'\n'; xPATH="$"; xFILES="`ls -al $|egrep "^-"|awk ''`"; for xFILE in $; do xITEM="$/$"; if [[ ! -r "$" ]] ; then echo "Path: '$' is not accessible! "; else nLINKS=$(ls -ld "$" | awk '') if [ $ -gt 1 ]; then iNODE=$(ls -id "$" | awk '' | head -1l) xDEVICE=$(df "$" | tail -1l | awk '') echo -e "\nItem: $[$iNODE] = $"; find $ -inum $ 2>/dev/null|egrep -v "$"|sed 's/^/ -> /'; fi fi done IFS="$"; echo ""; 
Ich habe Kommentare zu diesem Skript als separate Antwort gepostet. Daniel Andersson vor 11 Jahren 0
1
Charles

Eine GUI-Lösung kommt Ihrer Frage sehr nahe:

Sie können die tatsächlichen Hardlink-Dateien nicht unter "ls" auflisten, da, wie in früheren Kommentatoren darauf hingewiesen wurde, die Dateinamen "Dateinamen" nur Aliasnamen für dieselben Daten sind. Es gibt jedoch tatsächlich ein GUI-Tool, das dem, was Sie möchten, sehr nahe kommt, nämlich eine Pfadliste von Dateinamen, die auf dieselben Daten (als Hardlinks) unter Linux verweisen, die als FSLint bezeichnet wird. Die gewünschte Option befindet sich unter "Namenskollisionen" -> Deaktivieren Sie "Checkbox $ PATH" in Search (XX) -> und wählen Sie "Aliases" aus dem Dropdown-Feld nach "für ..." in Richtung Mitte.

FSLint ist sehr schlecht dokumentiert, aber ich habe festgestellt, dass der eingeschränkte Verzeichnisbaum unter "Suchpfad" mit dem Kontrollkästchen "Recurse?" und die zuvor genannten Optionen, eine Liste von fest verbundenen Daten mit Pfaden und Namen, die auf dieselben Daten "zeigen", werden nach den Programmsuchen erzeugt.

FSlint kann unter http://www.pixelbeat.org/fslint/ gefunden werden. mklement0 vor 9 Jahren 0
1
Daniel Sokolowski

Sie können lsHardlinks mit einem 'Alias' markieren, aber wie bereits erwähnt, gibt es keine Möglichkeit, die 'Quelle' des Hardlinks anzuzeigen, weshalb ich anhange .hardlink, um damit zu helfen.

markieren Sie Hardlinks

Fügen Sie Folgendes irgendwo in Ihrem hinzu .bashrc

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'