1.
Der erste:
for f in *; do
echo "$f"
done
nicht für Dateien genannt -n
, -e
und Varianten wie -nene
und 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 find
nichts 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 printf
es 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)
bash
Soweit 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- -print0
Nicht-Standard-Erweiterung).
Das beinhaltet immer noch das Aufrufen eines Suchbefehls und die Verwendung einer langsamen while read
Schleife. Es ist daher wahrscheinlich langsamer als die Verwendung der for
Schleife, es sei denn, die Liste der Dateien ist riesig.
4.
Im Gegensatz zur Shell-Platzhaltererweiterung find
wird lstat
bei jeder Datei ein Systemaufruf ausgeführt, sodass es unwahrscheinlich ist, dass das Nichtsortieren dies kompensiert.
Mit GNU / BSD find
kann dies vermieden werden, indem die -maxdepth
Erweiterung 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 find
die 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 find
alle Dateien gefunden wurden. Auf GNU- und FreeBSD-Systemen kann dies möglicherweise stdbuf
schneller geschehen (Deaktivieren der Stdio-Pufferung).
5.
Die POSIX / standard / portable-Methode zum Ausführen von Befehlen für jede Datei find
besteht darin, das -exec
Prädikat zu verwenden:
find . ! -name . -prune ! -name '.*' -exec some-cmd {} ';'
In diesem Fall echo
ist dies jedoch weniger effizient als das Schleifen in der Shell, da die Shell über eine integrierte Version von echo
while verfügt find
, die einen neuen Prozess erzeugen und /bin/echo
in 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 cmd2
wird nur ausgeführt, wenn cmd1
es 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, echo
da wir die sh
eingebaute -exec +
Version verwenden und die Version so wenig sh
wie 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 bash
viel 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 .