1.
Der erste:
for f in *; do
echo "$f"
done
nicht für Dateien genannt -n, -eund Varianten wie -neneund mit einigen bash - Implementierungen mit Dateinamen Schrägstriche enthalten.
Der Zweite:
find * -prune | while read f; do
echo "$f"
done
nicht noch mehr Fälle (Dateien genannt !, -H, -name, , (die mit Leerzeichen oder Zeilenumbrüche starten, Dateinamen oder Ende enthalten ...)
Es ist die Shell, die sich erweitert *und findnichts anderes tut, als die Dateien zu drucken, die sie als Argumente erhält. Sie hätten printf '%s\n'stattdessen auch verwenden können, was, wie printfes eingebaut ist, auch den zu vielen Argumenten möglichen Fehler vermeidet .
2.
Die Erweiterung von *ist sortiert, Sie können es etwas schneller machen, wenn Sie die Sortierung nicht benötigen. In zsh:
for f (*(oN)) printf '%s\n' $f
oder einfach:
printf '%s\n' *(oN)
bashSoweit ich das beurteilen kann, gibt es kein Äquivalent, weshalb Sie darauf zurückgreifen müssen find.
3.
find . ! -name . -prune ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
(oben unter Verwendung einer GNU / BSD- -print0Nicht-Standard-Erweiterung).
Das beinhaltet immer noch das Aufrufen eines Suchbefehls und die Verwendung einer langsamen while readSchleife. Es ist daher wahrscheinlich langsamer als die Verwendung der forSchleife, es sei denn, die Liste der Dateien ist riesig.
4.
Im Gegensatz zur Shell-Platzhaltererweiterung findwird lstatbei jeder Datei ein Systemaufruf ausgeführt, sodass es unwahrscheinlich ist, dass das Nichtsortieren dies kompensiert.
Mit GNU / BSD findkann dies vermieden werden, indem die -maxdepthErweiterung verwendet wird, die eine Optimierung auslöst, bei der Folgendes gespeichert wird lstat:
find . -maxdepth 1 ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
Da finddie Ausgabe von Dateinamen beginnt, sobald sie gefunden wurden (mit Ausnahme der Stdio-Ausgabepufferung), ist es möglicherweise schneller, wenn die Ausführung in der Schleife zeitaufwändig ist und die Liste der Dateinamen mehr als ein Stdio-Puffer ist (4) / 8 kB). In diesem Fall beginnt die Verarbeitung in der Schleife, bevor findalle Dateien gefunden wurden. Auf GNU- und FreeBSD-Systemen kann dies möglicherweise stdbufschneller geschehen (Deaktivieren der Stdio-Pufferung).
5.
Die POSIX / standard / portable-Methode zum Ausführen von Befehlen für jede Datei findbesteht darin, das -execPrädikat zu verwenden:
find . ! -name . -prune ! -name '.*' -exec some-cmd {} ';'
In diesem Fall echoist dies jedoch weniger effizient als das Schleifen in der Shell, da die Shell über eine integrierte Version von echowhile verfügt find, die einen neuen Prozess erzeugen und /bin/echoin jeder Datei ausführen muss.
Wenn Sie mehrere Befehle ausführen müssen, haben Sie folgende Möglichkeiten:
find . ! -name . -prune ! -name '.*' -exec cmd1 {} ';' -exec cmd2 {} ';'
Aber Vorsicht, das cmd2wird nur ausgeführt, wenn cmd1es erfolgreich ist.
6.
Eine kanonische Möglichkeit, komplexe Befehle für jede Datei auszuführen, ist der Aufruf einer Shell mit -exec ... {} +:
find . ! -name . -prune ! -name '.*' -exec sh -c '
for f do
cmd1 "$f"
cmd2 "$f"
done' sh {} +
Diesmal sind wir wieder effizient, echoda wir die sheingebaute -exec +Version verwenden und die Version so wenig shwie möglich erscheint.
7.
In meinen Tests mit einem Verzeichnis mit 200.000 Dateien mit Kurznamen auf ext4 ist das Verzeichniszsh (Absatz 2) bei weitem das schnellste, gefolgt von der ersten einfachen for i in *Schleife (obwohl dies wie üblich bashviel langsamer ist als andere Shells).
findöffnet die gefundenen Dateien nicht. Das einzige, was ich hier in Bezug auf eine große Anzahl von Dateien sehen kann, ist ARG_MAX .