私は多くの(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 globstar
set -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
使用しません。)