検索用のループ用のBashスクリプトと多くのディレクトリ

検索用のループ用のBashスクリプトと多くのディレクトリ

私は多くの(100,000+)のサブディレクトリを含むディレクトリでいくつかのタスクを実行するためのbashスクリプトを書いています。以下のようにforループに渡すことができるパラメータの数に事前定義された制限はありますか?

for dir in $(find . -type d)
do
  # My code
done

findコマンドがあまりにも多くのディレクトリを返すと、スクリプトが失敗するのではないかと心配されます。

答え1

find出力を解析するのではなく、シェルワイルドカードのみを使用してください。これはより安全で、シェルに組み込まれています。シェル組み込み(for外部プロセスなど)は呼び出しを行わないため、外部プロセスと同じパラメータリスト長制限は適用されませんexec*

for dir in ./*/; do
    # ...
done

答え2

ある場合は、bash 4次の再帰的な操作を実行できます。

shopt -s globstar
for dir in **/; do echo "$dir"; done

答え3

あなたが受け入れた回答に同意しません。〜する$(find)使用すると、プレゼントがなくてもメモリの問題が発生しますexec

代わりに、次のように書いてください。

find . -type d | while IFS= read -r dir
do
  # My code
done

(注:これは改行文字を含むディレクトリ名がないと仮定します。)

findこれにより、コマンド置換のように出力を保存するために一時メモリを使用する必要がなくなります。このコマンドfindや他のコマンドが終了しない場合でも機能します。たとえば、次のようになります。

# will not work!
for line in $(yes) ; do echo "$line" ; done

# works
yes | while IFS= read -r line ; do echo "$line" ; done

答え4

ファイル名を生成するためにコマンド置換を使用しないでください。ファイル名にスペースが含まれているか\[?*

bash ≥4、ksh93、またはzshの場合は、globを使用してすべての深さのサブディレクトリと一致させることで、ほとんどまたは述部のfind使用-type dを回避できます。 Bashでは、まず実行してください。 kshで最初に実行します。-name …**shopt -s globstarset -o globstar

for dir in **/; do …; done

ポータブル、さらに必要な場合、またはfind … -exec … +を使用してくださいfind … -print0 | xargs -0 …。このアプローチのもう一つの利点は、findファイルに対する操作とある程度並列に実行されることです。ただし、これは巨大なディレクトリツリー(少なくとも数千の一致するファイル)でのみ機能します。コマンドの実行以上の操作が必要な場合は、findシェルを作成または実行できます。xargs

find -type d -exec sh -c 'for x in "$@"; do echo "$x"; done' _ {} +

(これはシェルピースに_あるので$0使用しません。)

関連情報