再帰ディレクトリでの高速文字列の置き換え

再帰ディレクトリでの高速文字列の置き換え

どうやって作れますか?早くテキスト変えるそして再帰的ディレクトリとファイル名スペースそしてアポストロフィ?標準のUNIXツールまたはよく知られているソフトウェアパッケージを使用するのが最善です。

これを使用すると、各ファイルに対して新しいプロセスが作成されるため、多くのファイルで非常に遅くなりますfind。したがって、ディレクトリの巡回と文字列の置換を単一のタスクに統合する方法を探しています。

遅い検索:

find . -name '*.txt'  -exec grep foo {} \;

クイック検索:

grep -lr --include=*.txt foo

遅い交換:

find . -name '*.txt' -exec perl -i -pe 's/foo/bar/' {} \;

クイック交換:

# Your suggestion here

(これは非常に高速ですが、2回のパスが必要で、スペースを処理しません。)

perl -p -i -e 's/foo/bar/g' `grep -lr --include=*.txt foo`

答え1

あなたはちょうど次を使用したいと思います:

 find . -name '*.txt'  -exec cmd {} \;

cmd1 つの引数のみを受け入れる s 形式です。そうではありませんgrep。そしてgrep

 find . -name '*.txt'  -exec grep foo /dev/null {} +

(または-HGNUで使用されますgrep)。詳しくは以下をご覧ください。再帰 grep と find/-type f -exec grep{}\;どちらがより効率的で速いですか?

これで、置き換えのためにこれは同じで、複数のperl -pi引数を使用します。

 find . -name '*.txt' -type f -exec perl -pi -e s/foo/bar/g {} +

これで、これらのファイルは含めるかどうかにかかわらず上書きされますfoo。代わりに、次のようにします(GNUgrepおよびxargs/または互換性の前提)。

 find . -name '*.txt' -type f -exec grep -l --null foo {} + |
   xargs -r0 perl -pi -e s/foo/bar/g

または:

 grep -lr --null --include='*.txt' foo . |
   xargs -r0 perl -pi -e s/foo/bar/g

したがって、埋め込みファイルのみがfoo書き換えられます。


ところで、別のGNU拡張はシェルグローブなので、引用する必要があります--include=*.txt--includeたとえば、--include=foo.txt呼び出されている現在のディレクトリにファイルがある場合、シェルは呼び出す--include=*.txt前にそのファイルに展開されますgrep。それ以外の場合、多くのシェルでは、globがファイルと一致しないというエラーが発生します。

だからあなたは欲しいでしょうgrep --include='*.txt'

答え2

式が簡単な場合は、findシェルを使用してワイルドカードを使用できます。発生する主な制限は、コマンドラインで受け入れられるよりも多くのファイルを処理することです。

Bashの例:

$ shopt -s globstar

$ date > a.txt
$ date > b.txt
$ date > c.txt
$ cat *.txt
Thu Mar 29 14:57:57 EDT 2018
Thu Mar 29 14:58:00 EDT 2018
Thu Mar 29 14:58:02 EDT 2018
$ mkdir -p deep/sub/dir
$ mv *.txt deep/sub/dir

$ perl -pi -e 's/EDT/EST/' **/*.txt

$ cat deep/sub/dir/*.txt
Thu Mar 29 14:57:57 EST 2018
Thu Mar 29 14:58:00 EST 2018
Thu Mar 29 14:58:02 EST 2018

答え3

find ... -exec";"代わりに、「+」ターミネータを使用してファイルを一度に1つずつ実行するのではなく、一括で実行できます(exec実行中のコマンドが一度に複数のファイル呼び出しをサポートしている場合)。

find . -name '*.txt' -exec grep foo {} +
find . -name '*.txt' -exec perl -i -pe 's/foo/bar/' {} +

関連情報