Sind zwei Dateien fest miteinander verbunden?

27

Wie kann ich über die Befehlszeile feststellen, ob zwei Dateien fest miteinander verbunden sind? zB verlinke etwas dazu:

$ ls
fileA fileB fileC

$ is-hardlinked fileA fileB
yes

$ is-hardlinked fileA fileC
no
Vincent Scheib
quelle

Antworten:

37

Bei den meisten Dateisystemen¹ wird eine Datei eindeutig durch ihre Inode- Nummer bestimmt. Sie müssen also nur prüfen, ob die beiden Dateien dieselbe Inode-Nummer haben und sich auf demselben Dateisystem befinden.

Ash, ksh, bash und zsh haben ein Konstrukt, das die Prüfung für Sie durchführt: den Datei-Gleichheitsoperator -ef.

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

ls -i /path/to/fileListet für fortgeschrittenere Fälle die Inode-Nummer einer Datei auf. df -P /path/to/fileZeigt an, in welchem ​​Dateisystem sich die Datei befindet (wenn sich zwei Dateien im selben Verzeichnis befinden, befinden sie sich im selben Dateisystem). Wenn Ihr System den statBefehl hat, kann er wahrscheinlich die Inode- und Dateisystemnummern anzeigen ( statvariiert von System zu System, überprüfen Sie Ihre Dokumentation). Wenn Sie einen kurzen Blick auf harte Links in einem Verzeichnis werfen möchten, versuchen Sie es ls -i | sort(möglicherweise per Pipe an awk ).

¹ Alle nativen Unix-Dateisysteme und einige andere wie NTFS, aber möglicherweise keine exotischen Fälle wie CramFS.

Gilles 'SO - hör auf böse zu sein'
quelle
Und definitiv nicht auf irgendetwas FAT-basiertem, wo es als "vernetzte" Datei erkannt würde.
Ignacio Vazquez-Abrams
4
Beachten Sie, dass fileA -ef fileBauch 0(Erfolg) zurückgegeben wird, wenn fileAes sich um einen Symlink fileBhandelt oder umgekehrt, oder wenn beide auf dieselbe Datei verweisen.
Januar
Wie führen Sie den von Ihnen vorgeschlagenen Befehl aus? Ich habe versucht [.bashrc -ef .bash / .bashrc] und Variationen davon, aber es hat nicht wirklich funktioniert.
Charlie Parker
@ CharlieParker [ .bashrc -ef .bash/.bashrc ]ist richtig. Ohne Kontext habe ich natürlich keine Ahnung, warum es "nicht wirklich funktioniert" hat - Sie könnten die falschen Dateien vergleichen, Sie könnten das Ergebnis nicht richtig überprüfen, Sie könnten eine Shell ohne -ef...
Gilles "SO - hör auf böse zu sein"
2
@CharlieParker Der Befehl ist eigentlich [und ist ein Synonym für test. Aber man [oder man testgibt Ihnen die Manpage des externen Befehls, während fast jede Shell einen eingebauten Befehl mit leicht unterschiedlichen Optionen hat, so dass Sie diesen im Handbuch Ihrer Shell nachschlagen müssen.
Gilles 'SO- hör auf böse zu sein'
4
function is-hardlinked() {
    r=yes
    [ "`stat -c '%i' $1`" != "`stat -c '%i' $2`" ] && r=no
    echo $r
}
x-way
quelle
6
Beachten Sie, dass dies falsch positiv sein kann, wenn sich die beiden Dateien auf unterschiedlichen Dateisystemen befinden, aber zufällig denselben Inode haben. Sie müssen auch die Gerätenummer testen ( stat -c %d). Und wenn Sie unter Linux arbeiten (mit Ihrem statBefehl), muss Ihre Shell [ fileA -ef fileB ]dies alles direkt erledigen. Außerdem bricht Ihr Befehl unbeabsichtigt mit Dateinamen, die Whitespace enthalten \[?*, oder beginnt mit -: Setzen Sie Befehlsanweisungen ( "$(stat -c %i -- "$1")") immer in doppelte Anführungszeichen .
Gilles 'SO - hör auf böse zu sein'
1
Warum würden Sie eine Menge umständlicher, aber portabler Konstrukte verwenden und dann das ausgesprochen nicht portierbare functionSchlüsselwort mit einem Funktionsnamen, der (weil er einen Bindestrich enthält) gegen POSIX-Konventionen für zulässige Namen verstößt?
Charles Duffy
Sie haben vergessen, Ihre $1und zu zitieren $2. Möglicherweise möchten Sie auch die $()Syntax anstelle von Backticks verwenden, da die Klammern deutlich machen, wo der Befehl beginnt und wo er endet, und die Verschachtelung einfacher ist.
josch
3

Wie das erste Poster zeigt, können Sie unter Linux ein Skript schreiben, das auf so etwas basiert:

stat -c '%i' fileA fileB fileC
Nicht jetzt
quelle
4
Dies ist nicht genug: Sie erhalten die gleiche Nummer für die beiden Dateien, wenn Sie sich auf verschiedenen Dateisystemen befinden, aber zufällig den gleichen Inode haben. Sie müssen auch die Gerätenummer testen ( stat -c %d). Und wenn Sie unter Linux arbeiten (mit Ihrem statBefehl), muss Ihre Shell [ fileA -ef fileB ]dies alles direkt erledigen.
Gilles 'SO - hör auf böse zu sein'
0

find(1)Ab GNU- Version 4.2.11 können Sie auch Folgendes verwenden:

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

Wenn fileAdie gleiche Datei wie fileBdann finddruckt „Ja“ und die Bedingung wahr wird.

Im Gegensatz zur Verwendung des Gleichheitsoperators wird -efhierdurch ein neuer Prozess ausgelöst.

josch
quelle