特定の検索条件に基づいてファイル内の文字列を置き換えることは、非常に一般的なタスクです。どうすればよいですか
- 文字列
foo
を置き換えますバー
付き 現在のディレクトリ内のすべてのファイルにありますか? - サブディレクトリに対して同じことを再帰的に実行しますか?
- ファイル名が別の文字列と一致する場合にのみ置き換えますか?
- 文字列が特定のコンテキストで見つかった場合にのみ置き換えますか?
- 文字列が特定の行番号にある場合は置き換えますか?
- 複数の文字列を同じ置換で置き換えます
- 複数の文字列を異なる置換で置き換えます
承認された回答:
1。現在のディレクトリ内のすべてのファイルで、ある文字列のすべての出現箇所を別の文字列に置き換える:
これらは、知っている場合のためのものです。 ディレクトリには通常のファイルのみが含まれており、非表示になっていないすべてのファイルを処理する必要があります。そうでない場合は、2のアプローチを使用してください。
すべてのsed
この回答のソリューションは、GNU sed
を想定しています 。 FreeBSDまたはmacOSを使用している場合は、 -i
を置き換えます -i''
を使用 。 -i
の使用にも注意してください sed
の任意のバージョンに切り替えます ファイルシステムのセキュリティに一定の影響があるため、配布する予定のスクリプトではお勧めできません。
-
非再帰的、このディレクトリ内のファイルのみ:
sed -i -- 's/foo/bar/g' * perl -i -pe 's/foo/bar/g' ./*
( perl
|
で終わるファイル名の場合は失敗します またはスペース))。
-
再帰的な通常のファイル(非表示のファイルを含む )このサブディレクトリとすべてのサブディレクトリ
find . -type f -exec sed -i 's/foo/bar/g' {} +
zshを使用している場合:
sed -i -- 's/foo/bar/g' **/*(D.)
(リストが大きすぎると失敗する可能性があります。
zargs
を参照してください。 回避するために)。Bashは通常のファイルを直接チェックできません。ループが必要です(中かっこはオプションをグローバルに設定しないようにします):
( shopt -s globstar dotglob; for file in **; do if [[ -f $file ]] && [[ -w $file ]]; then sed -i -- 's/foo/bar/g' "$file" fi done )
ファイルは、実際のファイル(-f)であり、書き込み可能(-w)の場合に選択されます。
2。ファイル名が別の文字列と一致する/特定の拡張子を持つ/特定のタイプである場合にのみ置換します:
-
非再帰的な、このディレクトリ内のファイルのみ:
sed -i -- 's/foo/bar/g' *baz* ## all files whose name contains baz sed -i -- 's/foo/bar/g' *.baz ## files ending in .baz
-
このサブディレクトリとすべてのサブディレクトリにある再帰的な通常のファイル
find . -type f -name "*baz*" -exec sed -i 's/foo/bar/g' {} +
bashを使用している場合(中かっこはオプションをグローバルに設定しないようにします):
( shopt -s globstar dotglob sed -i -- 's/foo/bar/g' **baz* sed -i -- 's/foo/bar/g' **.baz )
zshを使用している場合:
sed -i -- 's/foo/bar/g' **/*baz*(D.) sed -i -- 's/foo/bar/g' **/*.baz(D.)
-コード>
sed
に伝えるのに役立ちます コマンドラインでこれ以上フラグが指定されないようにします。これは、-
で始まるファイル名から保護するのに役立ちます 。
-
ファイルが特定のタイプの場合、たとえば実行可能ファイル(
man find
を参照) その他のオプションについて):find . -type f -executable -exec sed -i 's/foo/bar/g' {} +
zsh
:
sed -i -- 's/foo/bar/g' **/*(D*)
3。文字列が特定のコンテキストで見つかった場合にのみ置換します
-
foo
を置き換えますバー
付きbaz
がある場合のみ 後で同じ行に:sed -i 's/foo(.*baz)/bar1/' file
sed
で 、()
を使用 括弧内にあるものはすべて保存され、 1
でアクセスできます。 。このテーマにはさまざまなバリエーションがあります。このような正規表現の詳細については、こちらをご覧ください。
-
foo
を置き換えますバー
付きfoo
の場合のみ 入力ファイルの3d列(フィールド)にあります(空白で区切られたフィールドを想定):gawk -i inplace '{gsub(/foo/,"baz",$3); print}' file
( gawk
が必要です 4.1.0以降)。
-
別のフィールドには、
$ N
を使用してください ここで、N
関心のあるフィールドの番号です。別のフィールドセパレータの場合(:
この例では)使用:gawk -i inplace -F':' '{gsub(/foo/,"baz",$3);print}' file
perl
を使用した別のソリューション :
perl -i -ane '$F[2]=~s/foo/baz/g; $" = " "; print "@Fn"' foo
注:両方の awk
およびperl
解決策はファイルの間隔に影響します(先頭と末尾の空白を削除し、空白のシーケンスを一致する行の1つのスペース文字に変換します)。別のフィールドには、 $ F [N-1]
を使用します ここで、 N
は必要なフィールド番号であり、別のフィールドセパレータに使用します( $ "=": "
出力フィールドの区切り文字を:
に設定します ):
perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo
-
foo
を置き換えますバー
付き 4行目のみ:sed -i '4s/foo/bar/g' file gawk -i inplace 'NR==4{gsub(/foo/,"baz")};1' file perl -i -pe 's/foo/bar/g if $.==4' file
4。複数の置換操作:異なる文字列に置換
-
sed
を組み合わせることができます コマンド:sed -i 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
順序が重要であることに注意してください( sed's / foo / bar / g; s / bar / baz / g'
foo
に置き換えます baz
を使用 。
-
またはPerlコマンド
perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
-
パターンの数が多い場合は、パターンとその置換を
sed
に保存する方が簡単です。 スクリプトファイル:#! /usr/bin/sed -f s/foo/bar/g s/baz/zab/g
-
または、上記のパターンペアが多すぎて実行できない場合は、ファイルからパターンペアを読み取ることができます(1行に2つのスペースで区切られたパターン、$patternと$replacement):
while read -r pattern replacement; do sed -i "s/$pattern/$replacement/" file done < patterns.txt
-
パターンの長いリストや大きなデータファイルの場合は非常に遅くなるため、パターンを読み取って
sed
を作成することをお勧めします。 代わりにそれらからのスクリプト。以下は、 <<!>スペース<!>>を想定しています。 区切り文字は、 MATCH <<!>スペース<!>> REPLACEのリストを区切ります ファイルpattern.txt
で1行に1つずつ発生するペア :sed 's| *([^ ]*) *([^ ]*).*|s/1/2/g|' <patterns.txt | sed -f- ./editfile >outfile
上記の形式はほとんど任意であり、たとえば、 <<!>スペース<!>>は使用できません。 MATCHのいずれかで またはREPLACE 。ただし、この方法は非常に一般的です。基本的に、 sed
のような出力ストリームを作成できる場合 スクリプトを作成すると、そのストリームを sed
として調達できます。 sed
を指定してスクリプトを作成する のスクリプトファイルを-
として stdin。
-
同様の方法で複数のスクリプトを組み合わせて連結できます:
SOME_PIPELINE | sed -e'#some expression script' -f./script_file -f- -e'#more inline expressions' ./actual_edit_file >./outfile
POSIX sed
コマンドラインに表示される順序ですべてのスクリプトを1つに連結します。これらはいずれもn
で終わる必要はありません ewline。
-
grep
同じように機能します:sed -e'#generate a pattern list' <in | grep -f- ./grepped_file
-
固定文字列をパターンとして使用する場合は、正規表現のメタ文字をエスケープすることをお勧めします。 。これはかなり簡単に行うことができます:
sed 's/[]$&^*./[]/\&/g s| *([^ ]*) *([^ ]*).*|s/1/2/g| ' <patterns.txt | sed -f- ./editfile >outfile
5。複数の置換操作:複数のパターンを同じ文字列で置換します
-
foo
のいずれかを置き換えます 、バーコード> または
baz
foobar
を使用sed -Ei 's/foo|bar|baz/foobar/g' file
-
または
perl -i -pe 's/foo|bar|baz/foobar/g' file