2

ファイルのリストがあり、その中には名前にスペースが含まれているものもあり、次のように生成されます。

find . -iname "*hs" | grep foo

のような単一のプロセスに引数として渡すにはどうすればよいprocess name1 name2 ...ですか?

すべてのファイル名を個別の引数として単一のプロセスに渡したいので、標準的なfor f in *ソリューションは機能しません。

4

1 に答える 1

5
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

GNUgrep拡張-Z-z

それができない場合 (grep正規表現が複雑すぎる必要がある場合)、ヌルで区切られた「行」を読み取るfind(仮説的な?) バージョンがない限り、問題が発生します。grep

-Z,--null
通常ファイル名に続く文字の代わりにゼロバイト (ASCII NUL 文字) を出力します。たとえばgrep -lZ、通常の改行の代わりに、各ファイル名の後に 0 バイトを出力します。このオプションは、改行などの特殊な文字を含むファイル名が存在する場合でも、出力を明確にします。find -print0このオプションは、 perl -0sort -z、 などのコマンドで使用して xargs -0、任意のファイル名 (改行文字を含むものも含む) を処理できます。

これはほとんど望んでいるものですが、完全ではありません。POSIX 2008getdelim()関数が使用するツールになります。目的のために に-zオプションを追加し、にフィードする前にデータをフィルタリングするために使用します。grepgrep -lzZ ....find ... -print0xargs -0

上記の引用は Mac OS X 10.7.5 のマニュアル ページからのもので、GNUgrepはバージョン 2.5.1 です。もしかしたら、GNU のより新しいバージョンのgrep方が、役立つ機能を備えているのではないでしょうか?

そして見よ、GNU grep2.14は必要なオプションをサポートしています:

-z,--null-data
入力を一連の行として扱い、それぞれ改行の代わりに 0 バイト (ASCII NUL 文字) で終了します。-Zorオプションと同様に--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 -- *\ *

これは、名前にスペースを含むファイル名だけに展開されます。これは、この質問に対する回答をテストするために作成されたファイルを含むファイル名を持つディレクトリをクリーンアップするのに役立ちます。

于 2013-02-05T03:32:29.057 に答える