ファイルのリストがあり、その中には名前にスペースが含まれているものもあり、次のように生成されます。
find . -iname "*hs" | grep foo
のような単一のプロセスに引数として渡すにはどうすればよいprocess name1 name2 ...
ですか?
すべてのファイル名を個別の引数として単一のプロセスに渡したいので、標準的なfor f in *
ソリューションは機能しません。
find . -iname "*hs*" -exec grep foo {} +
find . -iname "*hs*" -print0 | xargs -0 grep foo
どちらも機能します。+
オプションでコマンドラインにグループ化されるファイルの数が実際よりも少ない場合を除き、最初の方法はもう少し効率的ですらあるかもしれませんxargs
。
シェル グロビングを介してファイル名を生成している場合は、次のようになります。
grep foo *hs*
ファイル名の間隔を保持します。を使用ls
して名前を生成することは非常に問題があります。
grep コマンドは、ファイル自体の内容を検索するのではなく、一括処理の前にファイル名のリストをフィルター処理することを目的としていました。
' hs ' と ' foo ' の両方に一致する名前が必要ですか? その場合、find
静止を使用するのが最善です:
find . \( -iname "*hs*" -a -iname "*foo*" \) -exec grep foo {} +
のブール機能を使用しますfind
。
grep
拡張-Z
と-z
それができない場合 (grep
正規表現が複雑すぎる必要がある場合)、ヌルで区切られた「行」を読み取るfind
(仮説的な?) バージョンがない限り、問題が発生します。grep
-Z
,--null
通常ファイル名に続く文字の代わりにゼロバイト (ASCII NUL 文字) を出力します。たとえばgrep -lZ
、通常の改行の代わりに、各ファイル名の後に 0 バイトを出力します。このオプションは、改行などの特殊な文字を含むファイル名が存在する場合でも、出力を明確にします。find -print0
このオプションは、perl -0
、sort -z
、 などのコマンドで使用してxargs -0
、任意のファイル名 (改行文字を含むものも含む) を処理できます。
これはほとんど望んでいるものですが、完全ではありません。POSIX 2008getdelim()
関数が使用するツールになります。目的のために に-z
オプションを追加し、にフィードする前にデータをフィルタリングするために使用します。grep
grep -lzZ ....
find ... -print0
xargs -0
上記の引用は Mac OS X 10.7.5 のマニュアル ページからのもので、GNUgrep
はバージョン 2.5.1 です。もしかしたら、GNU のより新しいバージョンのgrep
方が、役立つ機能を備えているのではないでしょうか?
そして見よ、GNU grep
2.14は必要なオプションをサポートしています:
-z
,--null-data
入力を一連の行として扱い、それぞれ改行の代わりに 0 バイト (ASCII NUL 文字) で終了します。-Z
orオプションと同様に--null
、このオプションを「sort -z」などのコマンドで使用して、任意のファイル名を処理できます。
find
無視してはならないもう 1 つのオプションは、find
コマンドで実行するスクリプトを作成することです。
find . -iname "*hs*" -exec ./list-foo +
list-foo
スクリプトの場所:
for arg in "$@"
do
case "$arg" in
(*foo*) echo "$arg";; # This will still cause problems
esac
done
これにより、ファイルが識別されます。これecho
は準最適です。名前を配列に取り込んでから、配列を使用して最終コマンドを呼び出す必要があるかもしれません。
array=( )
i=0
for arg in "$@"
do
case "$arg" in
(*foo*) array[$((i++))]="$arg";;
esac
done
if [ "$i" -gt 0 ]
then real_work "${array[@]}"
fi
real_work
実際の作業を行うプログラム (スクリプト?) はどこにありますか。list-foo
同じフィルタリング作業を何度も行うつもりでない限り、使い終わったら捨てることができます。
スペースをエスケープすることで、スペースを含む名前をグロブできます。
rm -i -- *\ *
これは、名前にスペースを含むファイル名だけに展開されます。これは、この質問に対する回答をテストするために作成されたファイルを含むファイル名を持つディレクトリをクリーンアップするのに役立ちます。