Finden Sie Suchanfragen innerhalb des angegebenen Pfades, wie angegeben. Also, wenn Sie eingeben ./, stimmte es nicht übereinfoo
Costas
@Costas: Ich verstehe das. Was ich nicht verstehe ist, warum es einen Unterschied gemacht hat, wenn ich den absoluten Weg dazu gebe find.
York
@York In bestimmten Situationen gibt es kein Verhalten, das immer richtig ist. Stellen Sie sich einen Symlink mit dem Namen vor bar, der auf eine Datei verweist, foodie sich außerhalb des Suchpfads befindet. Soll das passen oder nicht?
Hauke Laging
1
Die .und /tmp/foosind nicht gleich - es handelt sich um zwei verschiedene feste Links zu demselben Verzeichnis. find /tmp/foo/. -name 'foo'findet auch nichts.
Jimmy
@jimmij: Als ich ausgeführt habe find /tmp/foo -name 'foo', habe ich bash gebeten, im Verzeichnis /tmp/fooeine Datei zu finden , deren Name "foo" ist. Da das Verzeichnis /tmp/fooleer ist, sollte es nichts zurückgegeben haben. Ich verstehe nicht, warum es zurückkommt /tmp/foo. Auf der anderen Seite habe ich beim Ausführen find . -name 'foo'Bash gebeten, dasselbe zu tun, dh eine Datei im aktuellen Verzeichnis (die zufällig war) zu finden /tmp/foo, deren Name 'foo' ist, und sie gibt nichts zurück, was Sinn macht.
York
Antworten:
15
findDurchläuft die angegebenen Verzeichnisbäume und wertet den angegebenen Ausdruck für jede gefundene Datei aus. Die Durchquerung beginnt am angegebenen Pfad. Hier ist eine Zusammenfassung der Funktionsweise find . -name foo:
Erster Pfad in der Befehlszeile: .
Entspricht der Basisname ( .) dem Muster foo? Nein, also tu nichts.
Es kommt also vor, dass dies /tmp/fooein anderer Name für dasselbe Verzeichnis ist. Aber findweiß das nicht (und es soll nicht versuchen, es herauszufinden).
Ist der Pfad ein Verzeichnis? Ja, also überquere es. Zählen Sie die Einträge in auf .und führen Sie für jeden Eintrag den Durchlaufprozess durch.
Das Verzeichnis ist leer: Es enthält keinen anderen Eintrag als .und .., der findnicht rekursiv durchlaufen wird. Damit ist der Job beendet.
Und find /tmp/foo:
Erster Pfad in der Befehlszeile: /tmp/foo
Entspricht der Basisname ( foo) dem Muster foo? Ja, die Bedingung stimmt also überein.
Mit dieser Bedingung ist keine Aktion verknüpft. Führen Sie daher die Standardaktion aus, bei der der Pfad gedruckt wird.
Ist der Pfad ein Verzeichnis? Ja, also überquere es. Zählen Sie die Einträge in auf /tmp/foound führen Sie für jeden Eintrag den Durchlaufprozess durch.
Das Verzeichnis ist leer: Es enthält keinen anderen Eintrag als .und .., der findnicht rekursiv durchlaufen wird. Damit ist der Job beendet.
Es kommt also vor, dass .und /tmp/foodasselbe Verzeichnis sind, aber das reicht nicht aus, um zu gewährleisten, dass findbeide das gleiche Verhalten haben. Der findBefehl bietet Möglichkeiten zur Unterscheidung zwischen Pfaden zu derselben Datei. Das -namePrädikat ist eines davon. find /tmp/foo -name fooEntspricht dem Startverzeichnis sowie jeder darunter liegenden Datei, die aufgerufen wird foo. find . -name .nur entspricht das Startverzeichnis ( .kann nie während eines rekursiven Traversal zu finden).
"Es enthält keinen anderen Eintrag als. und .., der nicht rekursiv gefunden wird." Ich gehe davon aus, dass "nicht rekursiv quer" auf ".." verweist. Wenn das richtig ist, was würde dann "rekursiv transversal" im Kontext von ".." bedeuten?
Faheem Mitha
@FaheemMitha "nicht rekursiv durchlaufen" gilt für beide .und ... (Wenn es rekursiv finddurchlaufen wird ., wird es das Verzeichnis immer wieder durchlaufen und…) .und ..sind nicht nur spezielle Notationen, sondern werden als Verzeichniseinträge angezeigt.
Gilles 'SO - hör auf böse zu sein'
5
Es gibt keine Normalisierung der Befehlszeilenargumente, bevor die Tests angewendet werden. Daher unterscheiden sich die Ergebnisse je nach verwendetem Pfad (wenn Symlinks beteiligt sind):
cd /tmp
mkdir foo
ln -s foo bar
find /tmp/foo -name foo
find /tmp/bar -name foo
In "Ihrem Fall" würden beide Anrufe das gleiche Ergebnis liefern, was (verwirrender) sein könnte. Sie können verwenden, -mindepth 1wenn die Startpunkte ignoriert werden sollen (möglicherweise nicht POSIX).
-mindepth 1funktioniert. Ich verstehe jedoch immer noch nicht warum find . -name 'foo'und find /tmp/foo -name 'foo'verhalte mich anders.
York
2
(gnu) find zeigt alle Übereinstimmungen an, die innerhalb des Pfads gefunden wurden, der für den Befehl bereitgestellt wurde, da der Vergleich mit den Befehlszeilenargumenten beginnt und von dort aus tiefer in die Verzeichnisstruktur absteigt (daher werden -maxdepth 0die Tests nur auf die Basisebene oder die Befehlszeilenargumente beschränkt, während -mindepth 1Überspringt die Befehlszeilenargumente wie man finderläutert. Dies ist der Grund, warum find /tmp/foo -name 'foo'eine Übereinstimmung erzielt wird, selbst wenn das Verzeichnis selbst leer ist.
find . -name 'foo'Auf der anderen Seite wird kein Ergebnis .erzielt, da (Punkt) eine spezielle Datei ist, die wie ein Hardlink zu demselben Inode wirkt wie /tmp/foo- es ist wie ein separater (wenn auch spezieller) Dateiname und kein symbolischer Link oder Ausdruck, dem man unterliegt Pfadnamenerweiterung durch die Shell. Daher zeigt der erste Test, der von find auf die Befehlszeilenargumente im angegebenen Beispiel angewendet wird, keine Übereinstimmungen an, da er .tatsächlich nicht mit dem in definierten Namensmuster übereinstimmt -name 'foo'. Dies gilt auch nicht, /tmp/foo/.da ein Test für ein -nameMuster nur für den Basisnamen des Pfads durchgeführt wird (siehe man find), was auch hier der Fall ist ..
Obwohl dieses Verhalten aus Benutzersicht möglicherweise nicht zu erwarten ist oder intuitiv erscheint (und ja, es hat mich zunächst auch verwirrt), stellt es keinen Fehler dar, sondern entspricht der Logik und Funktionalität, die auf den Man- und Infoseiten für ( gnu) finden.
Ich habe versucht, Gilles 'Antwort zu kommentieren, aber es war zu lang, um in einen Kommentar zu passen. Aus diesem Grund stelle ich es als Antwort auf meine eigene Frage.
Gilles 'Erklärung (und auch die von Shevek) ist klar und sinnvoll. Der entscheidende Punkt hierbei ist, dass nicht nur findversucht wird, die Dateinamen für die Dateien innerhalb der angegebenen Pfade (rekursiv) abzugleichen, sondern auch versucht wird, den Basisnamen der angegebenen Pfade selbst abzugleichen.
Gibt es andererseits einen Beweis dafür, dass dies der Weg findist, der funktionieren soll, anstatt ein Fehler zu sein? Meiner Meinung nach wäre es besser, wenn die Ergebnisse dadurch nicht inkonsistent werden find .und find ABSOLUTE-PATHweil Inkonsistenzen immer verwirrend sind und Entwickler viel Zeit damit verschwenden könnten, herauszufinden, "was falsch war". In meinem Fall habe ich ein Skript geschrieben und der Pfad wurde einer Variablen entnommen. Damit mein Skript richtig funktioniert, kann ich mir vorstellen, zu schreiben find $path/. -name 'pattern'.
Schließlich denke ich, dass Sie konsistente Ergebnisse finderzielen können, indem Sie das immer .durch das aktuelle Verzeichnis ersetzen, bevor Sie fortfahren.
fooIn dem Verzeichnis, in dem Sie die relative Suche gestartet haben, ist kein Objekt benannt .
Sie gehen zu Recht davon aus, dass dies gfindfehlerhaft ist, /tmp/foowenn der absolute Name als Startverzeichnis verwendet wird.
Gfindhat verschiedene Abweichungen vom Standard, anscheinend haben Sie einen anderen gefunden. Wenn Sie eine standardkonformere Lösung wünschen, empfehle ich, sfinddass dies Teil der ist schilytools.
-namegilt für Verzeichnissuchergebnisse. Keiner der beiden von Ihnen genannten Fälle gibt einen Verzeichniseintrag foovon einer readdir()Operation zurück.
Ich vermute, das ist auch ein Fehler. Hier ist die Ausgabe von find --version: find (GNU findutils) 4.4.2 Copyright (C) 2007 Freie Software Foundation, Inc. Lizenz GPLv3 +: GNU GPL Version 3 oder höher < gnu.org/licenses/gpl.html >
York
Nun, ich habe Ihre Beispielbefehle mit find(POSIX-zertifiziert) überprüft gfindund sfind; Das Problem besteht nur, wenn Sie verwenden gfind. Wird unter Linux gfindnicht unter dem nativen Namen, sondern unter dem Namen installiert find.
schily
3
Die find /tmp/foo -name fooAusgabe ist korrekt /tmp/foo. (Cc @York) Dies ist das Verhalten von OpenBSD find, GNU find, BusyBox find, Solaris findund anderen POSIX-kompatiblen Dateien find(„Der Primärwert muss als wahr bewertet werden, wenn der Basisname des untersuchten Dateinamens mit dem Muster (…) übereinstimmt “ - wenn der Dateiname ist eine, die als Pfadoperand übergeben wird, es ist kein readdirAufruf beteiligt).
./
, stimmte es nicht übereinfoo
find
.bar
, der auf eine Datei verweist,foo
die sich außerhalb des Suchpfads befindet. Soll das passen oder nicht?.
und/tmp/foo
sind nicht gleich - es handelt sich um zwei verschiedene feste Links zu demselben Verzeichnis.find /tmp/foo/. -name 'foo'
findet auch nichts.find /tmp/foo -name 'foo'
, habe ich bash gebeten, im Verzeichnis/tmp/foo
eine Datei zu finden , deren Name "foo" ist. Da das Verzeichnis/tmp/foo
leer ist, sollte es nichts zurückgegeben haben. Ich verstehe nicht, warum es zurückkommt/tmp/foo
. Auf der anderen Seite habe ich beim Ausführenfind . -name 'foo'
Bash gebeten, dasselbe zu tun, dh eine Datei im aktuellen Verzeichnis (die zufällig war) zu finden/tmp/foo
, deren Name 'foo' ist, und sie gibt nichts zurück, was Sinn macht.Antworten:
find
Durchläuft die angegebenen Verzeichnisbäume und wertet den angegebenen Ausdruck für jede gefundene Datei aus. Die Durchquerung beginnt am angegebenen Pfad. Hier ist eine Zusammenfassung der Funktionsweisefind . -name foo
:.
.
) dem Musterfoo
? Nein, also tu nichts.Es kommt also vor, dass dies
/tmp/foo
ein anderer Name für dasselbe Verzeichnis ist. Aberfind
weiß das nicht (und es soll nicht versuchen, es herauszufinden)..
und führen Sie für jeden Eintrag den Durchlaufprozess durch..
und..
, derfind
nicht rekursiv durchlaufen wird. Damit ist der Job beendet.Und
find /tmp/foo
:/tmp/foo
foo
) dem Musterfoo
? Ja, die Bedingung stimmt also überein./tmp/foo
und führen Sie für jeden Eintrag den Durchlaufprozess durch..
und..
, derfind
nicht rekursiv durchlaufen wird. Damit ist der Job beendet.Es kommt also vor, dass
.
und/tmp/foo
dasselbe Verzeichnis sind, aber das reicht nicht aus, um zu gewährleisten, dassfind
beide das gleiche Verhalten haben. Derfind
Befehl bietet Möglichkeiten zur Unterscheidung zwischen Pfaden zu derselben Datei. Das-name
Prädikat ist eines davon.find /tmp/foo -name foo
Entspricht dem Startverzeichnis sowie jeder darunter liegenden Datei, die aufgerufen wirdfoo
.find . -name .
nur entspricht das Startverzeichnis (.
kann nie während eines rekursiven Traversal zu finden).quelle
.
und..
. (Wenn es rekursivfind
durchlaufen wird.
, wird es das Verzeichnis immer wieder durchlaufen und…).
und..
sind nicht nur spezielle Notationen, sondern werden als Verzeichniseinträge angezeigt.Es gibt keine Normalisierung der Befehlszeilenargumente, bevor die Tests angewendet werden. Daher unterscheiden sich die Ergebnisse je nach verwendetem Pfad (wenn Symlinks beteiligt sind):
In "Ihrem Fall" würden beide Anrufe das gleiche Ergebnis liefern, was (verwirrender) sein könnte. Sie können verwenden,
-mindepth 1
wenn die Startpunkte ignoriert werden sollen (möglicherweise nicht POSIX).quelle
-mindepth 1
funktioniert. Ich verstehe jedoch immer noch nicht warumfind . -name 'foo'
undfind /tmp/foo -name 'foo'
verhalte mich anders.(gnu) find zeigt alle Übereinstimmungen an, die innerhalb des Pfads gefunden wurden, der für den Befehl bereitgestellt wurde, da der Vergleich mit den Befehlszeilenargumenten beginnt und von dort aus tiefer in die Verzeichnisstruktur absteigt (daher werden
-maxdepth 0
die Tests nur auf die Basisebene oder die Befehlszeilenargumente beschränkt, während-mindepth 1
Überspringt die Befehlszeilenargumente wieman find
erläutert. Dies ist der Grund, warumfind /tmp/foo -name 'foo'
eine Übereinstimmung erzielt wird, selbst wenn das Verzeichnis selbst leer ist.find . -name 'foo'
Auf der anderen Seite wird kein Ergebnis.
erzielt, da (Punkt) eine spezielle Datei ist, die wie ein Hardlink zu demselben Inode wirkt wie/tmp/foo
- es ist wie ein separater (wenn auch spezieller) Dateiname und kein symbolischer Link oder Ausdruck, dem man unterliegt Pfadnamenerweiterung durch die Shell. Daher zeigt der erste Test, der von find auf die Befehlszeilenargumente im angegebenen Beispiel angewendet wird, keine Übereinstimmungen an, da er.
tatsächlich nicht mit dem in definierten Namensmuster übereinstimmt-name 'foo'
. Dies gilt auch nicht,/tmp/foo/.
da ein Test für ein-name
Muster nur für den Basisnamen des Pfads durchgeführt wird (sieheman find
), was auch hier der Fall ist.
.Obwohl dieses Verhalten aus Benutzersicht möglicherweise nicht zu erwarten ist oder intuitiv erscheint (und ja, es hat mich zunächst auch verwirrt), stellt es keinen Fehler dar, sondern entspricht der Logik und Funktionalität, die auf den Man- und Infoseiten für ( gnu) finden.
quelle
Ich habe versucht, Gilles 'Antwort zu kommentieren, aber es war zu lang, um in einen Kommentar zu passen. Aus diesem Grund stelle ich es als Antwort auf meine eigene Frage.
Gilles 'Erklärung (und auch die von Shevek) ist klar und sinnvoll. Der entscheidende Punkt hierbei ist, dass nicht nur
find
versucht wird, die Dateinamen für die Dateien innerhalb der angegebenen Pfade (rekursiv) abzugleichen, sondern auch versucht wird, den Basisnamen der angegebenen Pfade selbst abzugleichen.Gibt es andererseits einen Beweis dafür, dass dies der Weg
find
ist, der funktionieren soll, anstatt ein Fehler zu sein? Meiner Meinung nach wäre es besser, wenn die Ergebnisse dadurch nicht inkonsistent werdenfind .
undfind ABSOLUTE-PATH
weil Inkonsistenzen immer verwirrend sind und Entwickler viel Zeit damit verschwenden könnten, herauszufinden, "was falsch war". In meinem Fall habe ich ein Skript geschrieben und der Pfad wurde einer Variablen entnommen. Damit mein Skript richtig funktioniert, kann ich mir vorstellen, zu schreibenfind $path/. -name 'pattern'
.Schließlich denke ich, dass Sie konsistente Ergebnisse
find
erzielen können, indem Sie das immer.
durch das aktuelle Verzeichnis ersetzen, bevor Sie fortfahren.quelle
foo
In dem Verzeichnis, in dem Sie die relative Suche gestartet haben, ist kein Objekt benannt .Sie gehen zu Recht davon aus, dass dies
gfind
fehlerhaft ist,/tmp/foo
wenn der absolute Name als Startverzeichnis verwendet wird.Gfind
hat verschiedene Abweichungen vom Standard, anscheinend haben Sie einen anderen gefunden. Wenn Sie eine standardkonformere Lösung wünschen, empfehle ich,sfind
dass dies Teil der istschilytools
.-name
gilt für Verzeichnissuchergebnisse. Keiner der beiden von Ihnen genannten Fälle gibt einen Verzeichniseintragfoo
von einerreaddir()
Operation zurück.quelle
find --version
: find (GNU findutils) 4.4.2 Copyright (C) 2007 Freie Software Foundation, Inc. Lizenz GPLv3 +: GNU GPL Version 3 oder höher < gnu.org/licenses/gpl.html >find
(POSIX-zertifiziert) überprüftgfind
undsfind
; Das Problem besteht nur, wenn Sie verwendengfind
. Wird unter Linuxgfind
nicht unter dem nativen Namen, sondern unter dem Namen installiertfind
.find /tmp/foo -name foo
Ausgabe ist korrekt/tmp/foo
. (Cc @York) Dies ist das Verhalten von OpenBSDfind
, GNUfind
, BusyBoxfind
, Solarisfind
und anderen POSIX-kompatiblen Dateienfind
(„Der Primärwert muss als wahr bewertet werden, wenn der Basisname des untersuchten Dateinamens mit dem Muster (…) übereinstimmt “ - wenn der Dateiname ist eine, die als Pfadoperand übergeben wird, es ist keinreaddir
Aufruf beteiligt).