以下を使用すると、ディレクトリ内のファイルを再帰的に簡単に繰り返すことができます。
find . -type f -exec bar {} \;
しかし、上記の方法は、実行すべき条件分岐、ループなどが多いため、より複雑な作業には適していません。私はこれを上で使用しました:
while read line; do [...]; done < <(find . -type f)
しかし、これはあいまいな文字を含むファイルでは機能しないようです。
$ touch $'a\nb'
$ find . -type f
./a?b
これらのあいまいな文字をうまく処理する他の方法はありますか?
答え1
別の用途があります。安全find
:
while IFS= read -r -d '' -u 9
do
[Do something with "$REPLY"]
done 9< <( find . -type f -exec printf '%s\0' {} + )
(これはすべてのPOSIXで動作しますfind
が、シェル部分にはbashが必要です。* BSDとGNU findを使用すると代わりに-print0
findを使用できますが、-exec printf '%s\0' {} +
これは少し高速です。)
これにより、ループ内で標準入力を使用でき、次のように使用できます。どの道。
答え2
これを行う方法は簡単です。
find -exec sh -c 'inline script "$0"' {} \;
または...
find -exec executable_script {} \;
答え3
最も簡単で安全な方法は、シェルワイルドカードを使用することです。
$ for f in *; do printf ":%s:\n" "$f"; done
:a b:
:c
d:
:-e:
:e f:
h:
上記の内容をサブディレクトリ(bashから)にするには、このオプションを使用して名前が次に始まるファイルと一致するように設定するglobstar
こともできます。dotglob
.
$ 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:
bash 4.2までは、**/
シンボリックリンクがディレクトリに繰り返されることに注意してください。 bash 4.3以降は**/
ディレクトリにのみ再帰されますfind
。
もう一つの一般的な解決策は、次のようにfind -print0
使用することです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:
h:/g
ファイル名に\r
。
答え4
ポータブルで読み込みループを実行するのは少し難しいですが、特にbashの場合は、次のことを試してみることができます。これ。
関連部品:
while IFS= read -d $'\0' -r file ; do
printf 'File found: %s\n' "$file"
done < <(find . -iname 'foo*' -print0)
find
NUL文字(0x00)で区切られた出力を印刷し、バックスラッシュを他の文字のエスケープ()として処理せずに行()のトークン化を実行せずに、read
NULで区切られた行()を取得するように指示します。 0x00はUnixのファイル名またはパスには現れないバイトなので、すべての奇妙なファイル名の問題を処理する必要があります。-d $'\0'
-r
IFS=