grepと置換の方法


251

ディレクトリ内のすべてのファイルとサブディレクトリ内で指定された文字列を再帰的に検索し、この文字列を別の文字列に置き換える必要があります。

それを見つけるコマンドは次のようになるでしょう。

grep 'string_to_find' -r ./*

しかし、どのようにしてすべてのインスタンスstring_to_findを別の文字列に置き換えることができますか?


私はgrepがこれを実行できるとは信じていません(私は間違っている可能性があります)。より簡単な方法は、sedまたはperlを使用して置き換えを行うことです
Memento Mori

2
使用してみるsed -i 's/.*substring.*/replace/'
Eddy_Em 2013年

2
@Eddy_Em行全体をreplaceで置き換えます。グループ化を使用して、部分文字列の前後の行の部分をキャプチャし、それを置換行に配置する必要があります。sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
JStrahl 2014


回答:


248

もう1つのオプションは、findを使用してからsedに渡すことです。

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \;

34
OS X 10.10ターミナルでは、パラメーターへの適切な拡張文字列-iが必要です。たとえば、find /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;とにかく、マニュアルで説明されているのとは異なり、空の文字列を指定してもバックアップファイルが作成されます...
Eonil

10
「sed:REエラー:不正なバイトシーケンス」と表示されるのはなぜですか。はい、-i ""OS X用のを追加しました。それ以外の場合は機能します。
taco

2
macOS 10.12で不正なバイトシーケンスの問題があり、この質問/回答で問題が解決しました:stackoverflow.com/questions/19242275/…
abeboparebop 2017

3
これはすべてのファイルに影響を与えるため、ファイルの時間が変更されます。Windowsで行末をからCRLFに変換LFします。
jww

183

答えがわかりました。

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'

14
これにより、一致するファイルが2回スキャンgrepされsedます。findmethod を使用する方が効率的ですが、この方法はうまくいきます。
cmevoli 2013年

41
OS Xでは、これを機能さsed -i 's/str1/str2/g'せるsed -i "" 's/str1/str2/g'ためにに変更する必要があります。
jdf 2015

6
この方法で@cmevoli grepは、すべてのファイルを調べ、にsed一致するファイルのみをスキャンしますgrep。でfind、他の答えにおける方法であって、find最初のリストは、すべてのファイル、およびsedそのディレクトリ内のすべてのファイルをスキャンします。したがって、この方法は必ずしも遅くなるわけではなく、一致の数とsedgrepとの検索速度の違いに依存しますfind
joelostblom 16

4
この方法でOTOHを使用すると、実際に置き換える前にgrepが検出した内容をプレビューできるため、特に私のような正規表現n00bsの場合、失敗のリスクが大幅に軽減されます
Lennart Rolland

2
これは、grepの置換がsedより賢い場合にも役立ちます。たとえば、ripgrepは.gitignoreに従いますが、sedはそうしません。
user31389 2017年

43

次のようにすることもできます。

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

これは、現在のディレクトリに関連するすべてのファイルで文字列「windows」を検索し、各ファイルで文字列が出現するたびに「windows」を「linux」に置き換えます。


2
これgrepは、変更してはならないファイルがある場合にのみ役立ちます。sedすべてのファイルで実行すると、ファイルの変更日が更新されますが、一致するものがなければ、内容は変更されません。
Tripleee

@tripleee:には注意してください...しかし、一致がない場合は、[sedの]」変わらない内容を残して使用した場合。-i、私は信じているsed内容は変更されていないにもかかわらず、それが触れたすべてのファイルのファイル時刻を変更します。sedまた、行末を変換し、 。私は使用していないsedすべてのためのGitのレポでWindows上CRLFに変更されているLF
JWW

このコマンドでは、-iの後に「」が必要です。少なくともmacosxでは、インプレース置換が行われた後にバックアップファイルが作成されないことを示します。詳細については、manページを確認してください。バックアップが必要な場合は、ここに作成するファイルの拡張子を置きます。
spinyBabbler

31

これは私にとってOS Xで最もうまくいきます:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi

ソース:http : //www.praj.com.au/post/23691181208/grep-replace-text-string-in-files


これは完璧です!agでも動作します:ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi

@sebastiankeller Perlコマンドには最後のスラッシュがありません。これは構文エラーです。
Tripleee

3
なぜこれがsort -u偶数の部分なのですか?どのような状況でgrep -rl同じファイル名を2回生成すると予想しますか?
Tripleee 2017年

5

他のソリューションは正規表現構文を混ぜます。検索と置換の両方に perl / PCREパターンを使用し、一致するファイルのみを処理するには、これは非常にうまく機能します。

grep -rlZPi 'match1' | xargs -0r perl -pi -e 's/match2/replace/gi;'

どこmatch1とはmatch2、通常は同じであるがmatch1、例えばキャプチャグループ置換にのみ関連する、より高度な機能を削除するために簡略化することができます。

翻訳:grepこのPCREパターンに一致するファイルを再帰的にリストし、nulで区切ってファイル名の特殊文字を保護します。次にxargs、nulで区切られたリストを予期しているファイル名をパイプしますが、名前が受信されない場合は何もしません。そしてperl、一致が見つかった代替行を取得します。

バイナリファイルを無視するIスイッチを追加しgrepます。大文字と小文字を区別するマッチングでは、iスイッチをgrepiフラグを置換式に付加しますが、スイッチ自体ませんiperl


Perl自体は、ファイル構造を再帰的に処理することができます。実際、find2perlPerlに同梱されているツールで、この種のことをxargs巧妙に行うことはありません。
tripleee 2017年

@tripleee findはファイルの内容を検索せず、Perlプログラムを作成せずに一致するファイルのみを処理することがポイントです。
Walf

これは、行末を変換するというsedベースのソリューションの問題を回避するため、Windowsに最適なソリューションです。ありがとう!
JamHandy

4

通常はgrepではなく、sed -i 's/string_to_find/another_string/g'orを使用しperl -i.bak -pe 's/string_to_find/another_string/g'ます。


3

使用しているときに非常に注意してくださいfindsedgitのレポに!バイナリファイルを除外しないと、次のエラーが発生する可能性があります。

error: bad index file sha1 signature 
fatal: index file corrupt

このエラーを解決sedするにnew_stringは、をold_string。これは、置き換えられた文字列を元に戻すため、問題の最初に戻ります。

文字列を検索して置き換える正しい方法は、バイナリファイルを無視するためにスキップfindしてgrep代わりに使用することです。

sed -ri -e "s/old_string/new_string/g" $(grep -Elr --binary-files=without-match "old_string" "/files_dir")

@hobsのクレジット


1

これが私がすることです:

find /path/to/dir -type f -iname "*filename*" -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

これfilenameにより/path/to/dir、の下のファイル名に含まれるすべてのファイルが検索されます。見つかったすべてのファイルではなく、次の行を検索してsearchstring置換oldしますnew

ただしfilename、ファイル名に文字列が含まれている特定のファイルの検索を省略したい場合は、次のようにします。

find /path/to/dir -type f -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

これは上記と同じことを行いますが、下にあるすべてのファイルに対して /path/to/dir


0

別のオプションは、globstarでperlを使用することです。

(またはどこでも)を有効shopt -s globstar.bashrcすると、** globパターンがすべてのサブディレクトリとファイルを再帰的に照合なります。

したがって、使用perl -pXe 's/SEARCH/REPLACE/g' -i **すると再帰的に置き換えSEARCHられますREPLACEます。

-Xフラグはperlに「すべての警告を無効にする」ように指示します-これは、ディレクトリについて文句を言わないことを意味します。

globstarを使用すると、すべての子ファイルで拡張子を付けsed -i 's/SEARCH/REPLACE/g' **/*.extて置換SEARCHしたい場合などに使用できます。REPLACE.ext


「もう1つのオプションは、perlをglobstarで使用することです...」 -SolarisなどのPosixyマシンでは使用できません。それは私が特に探しています理由ですgrepsed
jww '25年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.