it-swarm.com.de

Wie können Sie den tatsächlichen Hardlink von ls sehen?

Ich renne

ln /a/A /b/B

Ich möchte im Ordner a sehen, wo die Datei A von ls verweist.

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

ls -i

und

ls -l

zeigt die Anzahl der Referenzen an (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 (.) an.

162
zzr

Es gibt keine 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 eine Inode. Der Inode wiederum enthält die Dateimetadaten und (Verweise auf) den tatsächlichen Dateiinhalt. Durch das Erstellen eines festen Links wird ein anderer Dateiname + Verweis auf denselben Inode erstellt. Diese Referenzen sind unidirektional (zumindest in typischen Dateisystemen) - der Inode behält nur eine Referenzanzahl bei. Es gibt keinen eigentlichen Weg, um herauszufinden, welcher der "ursprüngliche" Dateiname ist.

Übrigens heißt der Systemaufruf zum "Löschen" einer Datei unlink. Es wird nur ein Hardlink entfernt. Der Inode und die angehängten Daten 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' in der Shell verwenden, um diese Prüfung durchzuführen.

59

UNIX verfügt über feste und symbolische Links (die mit "ln" bzw. "ln -s" erstellt wurden). Symbolische Links sind einfach eine Datei, die den tatsächlichen Pfad zu einer anderen Datei enthält und Dateisysteme überqueren kann.

Harte Links gibt es schon seit den Anfängen von UNIX (an die ich mich sowieso erinnern kann und die schon eine ganze Weile zurückreichen). Dies sind zwei Verzeichniseinträge, die auf die genauen gleichen zugrunde liegenden Daten verweisen. Die Daten in einer Datei werden durch ihre inode angegeben. Jede Datei in einem Dateisystem verweist auf einen Inode, aber es ist nicht erforderlich, dass jede Datei auf einen eindeutigen Inode verweist - daher kommen harte Links.

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

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

Hier ist ein Skript, das genau das macht. Sie rufen es auf mit:

findhardlinks ~/jquery.js

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

[email protected]:~# ./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 Drehbuch.

#!/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
33
user53528
ls -l

Die erste Spalte enthält die Berechtigungen. In der zweiten Spalte wird die Anzahl der Unterelemente (für Verzeichnisse) oder die Anzahl der Pfade zu denselben Daten (Hardlinks, einschließlich der Originaldatei) zur Datei angegeben. Z.B:

[email protected]    2    [username]    [group]    [timestamp]     HardLink
[email protected]    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
24
eyelidlessness

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

Wenn Sie eine bestimmte Datei <THEFILENAME> haben und alle ihre über das Verzeichnis <TARGETDIR> verteilten Hardlinks kennen möchten (dies kann sogar das gesamte mit / bezeichnete Dateisystem sein)

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

Erweiterung der Logik, wenn Sie alle Dateien im <SOURCEDIR> kennen möchten, die mehrere feste Links über <TARGETDIR> haben:

find <SOURCEDIR> -type f -links +1   \
  -printf "\n\n %n HardLinks of file : %H/%f  \n"   \
  -exec find <TARGETDIR> -type f -samefile {} \; 
10

Es gibt viele Antworten mit Skripten, um alle Hardlinks in einem Dateisystem zu finden. Die meisten von ihnen machen dumme Dinge wie das Ausführen von find, um das gesamte Dateisystem nach -samefile für JEDE mehrfach verknüpfte Datei zu durchsuchen. Das ist verrückt; Alles, was Sie brauchen, ist nach Inode-Nummer zu sortieren und Duplikate auszudrucken.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Vielen Dank an @Tino für die Optimierung meines ursprünglichen Befehls zur Unterstützung einer FS-ID (%D) und zur Verarbeitung aller nicht verzeichnisbezogenen Dateitypen, nicht nur der regulären Dateien. Hier finden Sie mehrfach verknüpfte Symlinks, Pipes usw.)

Die Verwendung von ! -type d -links +1 bedeutet, 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 von mehreren Hardlinks enthält. Auf jeden Fall wird dies VIEL weniger CPU-Zeit in Anspruch nehmen, um das Dateisystem erneut zu durchlaufen 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 ?: Schaltet den Ausgang aus. uniq hat nur eine sehr eingeschränkte Unterstützung für die Feldauswahl, daher fülle ich die Find-Ausgabe auf und verwende eine feste Breite. 20 Zeichen sind breit genug für die maximal mögliche Inode- oder Gerätenummer (2 ^ 64-1 = 18446744073709551615). XFS wählt Inode-Nummern basierend auf dem Speicherort, an dem sie zugewiesen sind, und nicht zusammenhängend von 0, sodass große XFS-Dateisysteme> 32-Bit-Inode-Nummern haben können, auch wenn sie nicht über Milliarden von Dateien verfügen. Andere Dateisysteme haben möglicherweise 20-stellige Inode-Nummern, auch wenn sie nicht gigantisch sind.

TODO: Sortiert Gruppen von Duplikaten nach Pfad. Wenn Sie sie nach Einhängepunkt und dann nach Inode-Nummer sortiert haben, werden die Dinge gemischt, wenn Sie ein paar verschiedene Unterverzeichnisse haben, die viele Hardlinks haben. (d. h. Gruppen von Dup-Gruppen gehen zusammen, aber der Ausgang mischt sie auf).

Ein abschließender sort -k 3 sortiert die Zeilen separat und nicht die Zeilengruppen als einzelnen Datensatz. Die 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 Trick tun. tr kann nur für einzelne Zeichen verwendet werden, jedoch nicht für 2-> 1 oder 1-> 2 Muster. Perl würde es tun (oder nur innerhalb von Perl oder awk analysieren und sortieren). sed könnte auch funktionieren.

4
Peter Cordes

Dies ist eine Art Kommentar zu Torocoro-Machos eigener Antwort und seinem Skript, passt aber offensichtlich nicht in das Kommentarfeld.


Umschreiben Sie Ihr Skript mit einfacheren Methoden, um die Informationen zu finden, und verarbeiten Sie damit weniger Aufrufe.

#!/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 für einen einfachen Vergleich so ähnlich wie möglich zu halten.

Kommentare zu diesem und Ihrem Skript

  • Man sollte die $IFS-Magie immer vermeiden, wenn ein Glob ausreicht, da es unnötig verschlungen ist und Dateinamen tatsächlich Zeilenumbrüche enthalten können (aber in der Praxis meistens der erste Grund).

  • Sie sollten es vermeiden, ls und solche Ausgaben manuell zu analysieren, da dies Sie früher oder später beißen wird. Beispiel: In der ersten Zeile awk schlagen Sie alle Dateinamen mit Leerzeichen fehl.

  • printf wird am Ende oft Probleme ersparen, da es mit der %s-Syntax so robust ist. Außerdem haben Sie die volle Kontrolle über die Ausgabe und sind im Gegensatz zu echo auf allen all Systemen konsistent.

  • stat kann Ihnen in diesem Fall viel Logik ersparen.

  • GNU find ist mächtig.

  • Ihre head- und tail-Aufrufe könnten direkt in awk mit z. Befehl exit und/oder Auswahl der Variablen NR. Dies würde Prozessaufrufe einsparen, die die Leistung in hart arbeitenden Skripten fast immer stark beeinträchtigen.

  • Ihre egreps könnte genauso gut eine grep sein.

3

Basierend auf dem findhardlinks-Skript (umbenannt in hard-links) habe ich es ü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}"; 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 "";
2
Torocoro-Macho

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

Sie können die tatsächlich fest verknüpften Dateien von "ls" nicht auflisten, da die "Dateinamen", wie bereits von früheren Kommentatoren erwähnt, nur Aliase für dieselben Daten sind. Tatsächlich gibt es jedoch ein GUI-Tool, das dem, was Sie wollen, sehr nahe kommt und eine Pfadauflistung von Dateinamen anzeigt, die unter Linux auf dieselben Daten (als Hardlinks) verweisen. Es heißt FSLint. Die gewünschte Option befindet sich unter "Namenskonflikte" -> Deaktivieren Sie das Kontrollkästchen "$ PATH" in der Suche (XX) -> und wählen Sie "Aliase" aus dem Dropdown-Feld nach "für ..." in der oberen Mitte aus.

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

1
Charles

Sie können ls so konfigurieren, dass Hardlinks mithilfe eines 'Alias' hervorgehoben werden. Wie bereits erwähnt, kann die 'Quelle' des Hardlinks jedoch nicht angezeigt werden. Deshalb füge ich .hardlink hinzu, um dies zu erleichtern.

 highlight hardlinks

Fügen Sie Folgendes irgendwo in Ihren .bashrc ein

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