GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum ist das Durchschleifen der Ausgabe von Find eine schlechte Praxis?

Diese Frage ist inspiriert von

Warum wird die Verwendung einer Shell-Schleife zum Verarbeiten von Text als schlechte Praxis angesehen?

Ich sehe diese Konstrukte

for file in `find . -type f -name ...`; do smth with ${file}; done

und

for dir in $(find . -type d -name ...); do smth with ${dir}; done

wird hier fast täglich verwendet, auch wenn einige Leute sich die Zeit nehmen, diese Posts zu kommentieren und zu erklären, warum diese Art von Zeug vermieden werden sollte…
Die Anzahl solcher Posts zu sehen (und die Tatsache, dass diese Kommentare manchmal einfach ignoriert) Ich dachte, ich könnte genauso gut eine Frage stellen:

Warum läuft eine Schleife über find ‘s Output Bad Practice und wie man einen oder mehrere Befehle für jeden Dateinamen/Pfad, der von find zurückgegeben wird, richtig ausführt ?

Akzeptierte Antwort:

Das Problem

for f in $(find .)

kombiniert zwei unvereinbare Dinge.

find druckt eine Liste von Dateipfaden, die durch Zeilenumbrüche getrennt sind. While der Split+Glob-Operator, der aufgerufen wird, wenn Sie $(find .) verlassen In diesem Listenkontext ohne Anführungszeichen wird es auf die Zeichen von $IFS aufgeteilt (enthält standardmäßig Zeilenumbruch, aber auch Leerzeichen und Tabulator (und NUL in zsh )) und führt für jedes resultierende Wort ein Globbing durch (außer in zsh). ) (und sogar Klammererweiterung in ksh93- oder pdksh-Derivaten!).

Auch wenn du es schaffst:

IFS='
' # split on newline only
set -o noglob # disable glob (also disables brace expansion in pdksh
              # but not ksh93)
for f in $(find .) # invoke split+glob

Das ist immer noch falsch, da das Zeilenumbruchzeichen genauso gültig ist wie jedes andere in einem Dateipfad. Die Ausgabe von find -print ist einfach nicht zuverlässig nachbearbeitbar (außer mit einem komplizierten Trick, wie hier gezeigt). ).

Das bedeutet auch, dass die Shell die Ausgabe von find speichern muss vollständig und dann split+glob (was impliziert, dass diese Ausgabe ein zweites Mal im Speicher gespeichert wird), bevor Sie beginnen, die Dateien zu durchlaufen.

Beachten Sie, dass find . | xargs cmd hat ähnliche Probleme (dort Leerzeichen, Zeilenvorschub, einfaches Anführungszeichen, doppeltes Anführungszeichen und umgekehrter Schrägstrich (und mit einigen xarg Implementierungsbytes, die nicht Teil gültiger Zeichen sind) sind ein Problem)

Richtigere Alternativen

Die einzige Möglichkeit, einen for zu verwenden Schleife auf der Ausgabe von find wäre die Verwendung von zsh das unterstützt IFS=$'

Linux
  1. Warum akzeptiert Find „-exec Cp {} Dir +“ nicht?

  2. Ssh – Warum ist Firefox gegenüber SSH so langsam?

  3. Warum fügt die Ssh -t Option Cr &Lf in der umgeleiteten Ausgabe hinzu?

  4. Warum liefert Grep -o -w unter Mac OS X nicht die erwartete Ausgabe?

  5. Warum wird nach dem Beenden ein Ping ausgegeben?

Warum zeigt „weniger“ keine fette Ausgabe?

Iteration über jede Zeile der Ausgabe von ls -l

Warum wird diese Shell-Pipeline beendet?

Linux, warum kann ich find result nicht an rm weiterleiten?

Warum ist es so schwer, eine Datei in Ubuntu zu finden?

Wird sudo su - als schlechte Praxis angesehen?