x=$(find . -name "*.txt")
echo $x
上記のコードを Bash シェルで実行すると、リストではなく、空白で区切られた複数のファイル名を含む文字列が得られます。
もちろん、リストを取得するためにさらに空白で区切ることもできますが、もっと良い方法があるはずです。
では、コマンドの結果をループする最適な方法は何でしょうかfind
?
ベストアンサー1
TL;DR: 最も正しい答えだけを求めているのであれば、おそらく私の個人的な好みが知りたいでしょう (この投稿の下部を参照)。
# execute `process` once for each file
find . -name '*.txt' -exec process {} \;
時間があれば、残りの部分を読んで、いくつかの異なる方法とそのほとんどの問題点を確認してください。
完全な回答:
最適な方法は何をしたいかによって異なりますが、いくつかのオプションがあります。サブツリー内のファイルまたはフォルダーの名前に空白が含まれていない限り、ファイルをループするだけです。
for i in $x; do # Not recommended, will break on whitespace
process "$i"
done
わずかに改善するには、一時変数を削除できますx
。
for i in $(find . -name \*.txt); do # Not recommended, will break on whitespace
process "$i"
done
可能な場合は glob を使用する方がはるかに優れています。現在のディレクトリ内のファイルに対しては、空白文字は安全です。
for i in *.txt; do # Whitespace-safe but not recursive.
process "$i"
done
このglobstar
オプションを有効にすると、このディレクトリとすべてのサブディレクトリ内の一致するすべてのファイルを glob できます。
# Make sure globstar is enabled
shopt -s globstar
for i in **/*.txt; do # Whitespace-safe and recursive
process "$i"
done
場合によっては、たとえばファイル名がすでにファイル内にある場合、以下を使用する必要がありますread
。
# IFS= makes sure it doesn't trim leading and trailing whitespace
# -r prevents interpretation of \ escapes.
while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
process "$line"
done < filename
read
find
区切り文字を適切に設定することで、と組み合わせて安全に使用できます。
find . -name '*.txt' -print0 |
while IFS= read -r -d '' line; do
process "$line"
done
find
より複雑な検索を行うには、をオプション付きで-exec
、または とともに使用するとよいでしょう-print0 | xargs -0
。
# execute `process` once for each file
find . -name \*.txt -exec process {} \;
# execute `process` once with all the files as arguments*:
find . -name \*.txt -exec process {} +
# using xargs*
find . -name \*.txt -print0 | xargs -0 process
# using xargs with arguments after each filename (implies one run per filename)
find . -name \*.txt -print0 | xargs -0 -I{} process {} argument
find
-execdir
の代わりにを使用すると、コマンドを実行する前に各ファイルのディレクトリに cd することもできます。また、の代わりに(またはの代わりに)-exec
を使用して、対話型 (各ファイルに対してコマンドを実行する前にプロンプトを表示) にすることもできます。-ok
-exec
-okdir
-execdir
*: 技術的には、find
とxargs
(デフォルト) は両方とも、コマンド ラインに収まるだけの数の引数で、すべてのファイルを処理するのに必要な回数だけコマンドを実行します。実際には、非常に多くのファイルがない限り問題にはなりません。長さを超えていて、すべてを同じコマンド ラインで実行する必要がある場合は、 別の方法を見つける
しかありません 。