どうやって作れますか?早くテキスト変えるそして再帰的ディレクトリとファイル名スペースそしてアポストロフィ?標準の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 {} \;
cmd
1 つの引数のみを受け入れる s 形式です。そうではありませんgrep
。そしてgrep
:
find . -name '*.txt' -exec grep foo /dev/null {} +
(または-H
GNUで使用されます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/' {} +