
Ich möchte find
Dateien (mit ähnlichen Merkmalen) finden, aber bestimmten symbolischen Links folgen und nur diesen folgen (durch Mustervergleich).
Offenbar find
kommt es selbst nicht damit klar: Es gibt keine Option zum Einrichten des Symlink-Follow-Verhaltens, und eine naive Lösung find -L
funktioniert problemlos (oder ist extrem langsam).
Antwort1
Der letzte Satz der Frage lässt vermuten, dass das Problem nicht beim Verfolgen von Symlinks im Allgemeinen liegt (und z. B. beim Anwenden -newer
auf den Symlink in einem Fall und auf das Ziel in einem anderen Fall), sondern beim Verfolgen von Symlinkszu Verzeichnissenund somit dorthin zu gelangen, wo Sie nicht hinwollen.
ProSpezifikation, find
soll Endlosschleifen erkennen, sodass es nicht zu einem Livelock kommen sollte. Verschwendete Ressourcen (einschließlich Zeit) können ein Problem sein und ich verstehe Ihre Besorgnis.
Verwenden Sie zunächst, -L
um das Folgen von Symlinks zuzulassen find
, denen Sie folgen möchten. Dann benötigen Sie eine Möglichkeit, andere Symlinks zu erkennen.
In find -L
-type l
ist nie wahr, aber Sie können Symlinks mit erkennen -exec test -L {} \;
(denken Sie daran -exec … \;
, dass es sich auch um einen Test handelt. Er ist erfolgreich, wenn der innere Befehl mit dem Status 0 beendet wird). Auf diese Weise können Sie immer noch einige Tests speziell auf Symlinks anwenden und -prune
(oder nicht) entsprechend.
Beispielsweise führt der folgende Befehl nur symbolische Links aus, deren Namen mit beginnen foo
oder enden bar
:
find -L . -exec test -L {} \; ! \( -name 'foo*' -o -name '*bar' \) -prune -o -print
Platzieren Sie den Ausdruck, den Sie ursprünglich wollten, nach -prune -o
. Im obigen Befehl ist der „ursprüngliche“ Ausdruck -print
. Denken Sie daran , -exec
dass das implizite unterdrückt wird . -print
Wenn Sie es -print
also brauchen, fügen Sie es explizit hinzu (wie wir es getan haben).
Beachten Sie, dass -name
der Name des Symlinks selbst getestet wird. Wenn Sie den Namen des Ziels testen möchten, benötigen Sie realpath
möglicherweise basename
Shell-Code. Beispiel:
find -L . -exec test -L {} \; -exec sh -c '
case "$(basename "$(realpath "$1")")" in
baz* ) exit 0 ;;
*qux ) exit 1 ;;
esac
exit 0
' find-sh {} \; -prune -o -print
Der obige Befehl erstellt -prune
einen symbolischen Link zu allen Dateien, deren Name mit beginnt baz
, führt aber auch symbolische Links zu Verzeichnissen aus, deren Namen mit enden qux
(sofern sie nicht mit beginnen baz
), und schließlich -prune
zu allen anderen symbolischen Links.
Anmerkungen:
realpath
undbasename
sind nicht portierbar.realpath
löst alle symbolischen Links auf.- Das Verhalten im Falle eines defekten symbolischen Links entspricht möglicherweise Ihren Erwartungen, muss es aber nicht.
- Das separate Aufrufen
test
für jede Datei beeinträchtigt die Leistung, aber ich habe keine bessere Möglichkeit gefunden. Das Aufrufen vonsh
undrealpath
istbasename
in dieser Hinsicht ebenfalls schlecht, aber hier geschieht dies nur für symbolische Links, sodass die Auswirkungen in den meisten Fällen begrenzt sein werden. find-sh
wird hier erklärt:Was ist das zweite sh insh -c 'some shell code' sh
?-prune
In den Beispielen werden Pfadnamen, die d erhalten, nicht-print
bearbeitet. Ändern Sie das letzte Fragment in-prune -false -o -print
und sie werden gedruckt. SieheErläuterung-false
; für den Fall, dass Sie sie brauchen, gibt es eine tragbare Alternative .