
Das rekursive Durchlaufen der Dateien in einem Verzeichnis ist ganz einfach möglich durch:
find . -type f -exec bar {} \;
Das oben genannte funktioniert jedoch nicht für komplexere Dinge, bei denen viele bedingte Verzweigungen, Schleifen usw. durchgeführt werden müssen. Früher habe ich dies für das Obige verwendet:
while read line; do [...]; done < <(find . -type f)
Allerdings scheint dies bei Dateien mit obskuren Zeichen nicht zu funktionieren:
$ touch $'a\nb'
$ find . -type f
./a?b
Gibt es eine Alternative, die mit solch obskuren Zeichen gut umgehen kann?
Antwort1
Noch eine weitere Verwendung fürsicherfind
:
while IFS= read -r -d '' -u 9
do
[Do something with "$REPLY"]
done 9< <( find . -type f -exec printf '%s\0' {} + )
(Dies funktioniert mit jedem POSIX find
, aber der Shell-Teil erfordert Bash. Mit *BSD und GNU find können Sie -print0
anstelle von verwenden -exec printf '%s\0' {} +
, es ist etwas schneller.)
Dies ermöglicht die Verwendung der Standardeingabe innerhalb der Schleife und funktioniert mitbeliebigWeg.
Antwort2
Dies geht ganz einfach:
find -exec sh -c 'inline script "$0"' {} \;
Oder...
find -exec executable_script {} \;
Antwort3
Der einfachste (und dennoch sichere) Ansatz ist die Verwendung von Shell-Globbing:
$ for f in *; do printf ":%s:\n" "$f"; done
:a b:
:c
d:
:-e:
:e f:
h:
Um das Obige in Unterverzeichnisse rekursiv zu machen (in Bash), können Sie die globstar
Option verwenden; auch so eingestellt, dotglob
dass es mit Dateien übereinstimmt, deren Name mit beginnt .
:
$ shopt -s globstar dotglob
$ for f in **/*; do printf ":%s:\n" "$f"; done
:a b:
:c
d:
:-e:
:e f:
:foo:
:foo/file1:
:foo/file two:
h:
Beachten Sie, dass bis Bash 4.2 **/
in symbolische Links zu Verzeichnissen rekursiv vorgegangen wird. Seit Bash 4.3 **/
wird nur in Verzeichnisse rekursiv vorgegangen, wie z . B. find
.
Eine weitere gängige Lösung ist die Verwendung find -print0
mit xargs -0
:
$ touch -- 'a b' $'c\nd' $'e\tf' $'g\rh' '-e'
$ find . -type f -print0 | xargs -0 -I{} printf ":%s:\n" {}
h:/g
:./e f:
:./a b:
:./-e:
:./c
d:
Beachten Sie, dass dies h:/g
tatsächlich korrekt ist, da der Dateiname eine enthält \r
.
Antwort4
Es ist ein bisschen schwierig, Ihre Leseschleife portabel zu machen, aber für Bash im Besonderen können Sie etwas wie versuchenDas.
Relevanter Teil:
while IFS= read -d $'\0' -r file ; do
printf 'File found: %s\n' "$file"
done < <(find . -iname 'foo*' -print0)
Dies weist an find
, die Ausgabe durch NUL-Zeichen (0x00) getrennt zu drucken und durch read
NUL getrennte Zeilen abzurufen ( -d $'\0'
), ohne Backslashs als Escapezeichen für andere Zeichen zu verwenden ( -r
), und keine Worttrennung in den Zeilen vorzunehmen ( IFS=
). Da 0x00 ein Byte ist, das in Dateinamen oder Pfaden unter Unix nicht vorkommen kann, sollte dies alle Ihre seltsamen Dateinamenprobleme lösen.