ディレクトリ内のファイルを再帰的に繰り返す


15

ディレクトリ内のファイルの再帰的な反復は、次の方法で簡単に実行できます。

find . -type f -exec bar {} \;

ただし、上記は、多くの条件分岐、ループなどを行う必要があるより複雑なものには機能しません。私はこれを上記に使用していました。

while read line; do [...]; done < <(find . -type f)

ただし、これはあいまいな文字を含むファイルでは機能しないようです:

$ touch $'a\nb'
$ find . -type f
./a?b

そのようなあいまいな文字をうまく処理する代替手段はありますか?


1
find ... -exec bash -c 'echo filename is in \$0: "$0"' {} \;より良い方法です。
jw013 14年

あなたはこの問題を解決し、あなたの変更により、あなたのオリジナルデザインを保つことができるread lineにはIFS= read -r line。それを壊す唯一の文字は改行です。
パトリック

1
@Patrick、ただしファイル名には改行を含めることができます。それ-d $'\0'が好ましい理由です。
godlygeek

回答:


7

安全の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すると-exec printf '%s\0' {} +、の代わりに使用でき、わずかに高速になります。)

これにより、ループ内で標準入力を使用できるようになり、どのパスで機能します。


1
私はそれを調べなければならなかったので:「読み取り...名前が指定されていない場合、読み取られた行は変数REPLYに割り当てられます。」だからdo echo "Filename is '$REPLY'"
アンドリュー

9

これは次のように簡単です:

find -exec sh -c 'inline script "$0"' {} \;

または...

find -exec executable_script {} \;

5

最も単純な(まだ安全な)アプローチは、シェルグロビングを使用することです。

$ 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(0×00)NUL文字で区切られ、その出力を印刷する、及びread(NUL区切り線を取得するために-d $'\0'他の文字(のためのエスケープとしてバックスラッシュを処理せずに)-r)と行に任意の単語分割をしません(IFS=)。0x00はUnixのファイル名またはパスでは発生しないバイトなので、これはすべての奇妙なファイル名の問題を処理するはずです。


1
-d ''はと同等-d $'\0'です。
l0b0 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.