web-dev-qa-db-ja.com

grepとsedを使用して文字列を見つけて置換する

次を使用して、特定の文字列をディレクトリで再帰的に検索し、別の文字列に置き換えます。

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g'

これで問題ありません。唯一の問題は、文字列が存在しない場合、引数を取得しないため、sedが失敗することです。私はこれをANTで自動的に実行しており、sedが失敗するためビルドが失敗するため、これは私にとって問題です。

文字列が見つからない場合にフェイルプルーフにする方法はありますか?

私が使用できる1行のシンプルなソリューションに興味があります(grepまたはsedである必要はありませんが、これらのような一般的なUNIXコマンドを使用します)。

67
Michael

最初にfindsedを見つけるのではなく、oldstr-execを直接grepに使用できます。多分少し効率が悪いかもしれませんが、それは重要ではないかもしれません。このように、sed置換はfindでリストされたすべてのファイルに対して実行されますが、oldstrが存在しない場合、明らかに動作しません。

find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
70

あなたのソリューションは大丈夫です。この方法でのみ試してください:

files=$(grep -rl oldstr path) && echo $files | xargs sed....

そのため、grepが0を返すときにのみxargsを実行します。一部のファイルで文字列が見つかったとき。

9
jm666

Vladのアイデアを取り入れて、少し変更しました。の代わりに

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

どちらが得られますか

sed: couldn't edit /dev/null: not a regular file

リモートサーバーへの3つの異なる接続で実行しています

touch deleteme
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' ./deleteme
rm deleteme

これはエレガントではなく、サーバーへの接続がさらに2つ必要です(すべてを1行で行う方法があるかもしれません)。

7
Michael

標準xargsには適切な方法がありません。他の人が示唆したようにfind -execを使用するか、引数がない場合は何もしないスクリプトでsedをラップする方が良いでしょう。 GNU xargsには--no-run-if-emptyオプションがあり、BSD/OS X xargsには-Lオプションがあり、似たような動作をするはずです。

7
geekosaur

-execを使用しなくても、何も見つからない場合に少なくとも1つの引数として/dev/nullを指定することができます。

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
4
user405725

私のユースケースでは、foo:/Drive_Letterfoo:/bar/baz/xyzに置き換えたいと思いました。私の場合、次のコードでそれを行うことができました。大量のファイルがあった同じディレクトリの場所にいました。

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

お役に立てば幸いです。

1
neo7