GNU/Linux >> Linux の 問題 >  >> Linux

ファイル内の文字列を置き換える方法は?

特定の検索条件に基づいてファイル内の文字列を置き換えることは、非常に一般的なタスクです。どうすればよいですか

  • 文字列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
    

Linux
  1. Sedを使用して複数行の文字列を置き換える方法は?

  2. 文字列をSedのスラッシュを含む文字列に置き換える方法は?

  3. sed のようなテキストを python に置き換えるにはどうすればよいですか?

  1. bashのフォルダ内の各ファイルの先頭に文字列を追加するにはどうすればよいですか?

  2. tr コマンド - 文字列 \n を実際の改行 (\n) に置き換える方法

  3. sed:見つかった場合は行を置き換えるか、見つからない場合はファイルの最後に追加する方法は?

  1. 文字列(ファイルではなく)をOpensslに渡す方法は?

  2. テキスト ファイル内の文字列を削除する

  3. 文字を再帰的にsedに置き換える方法は?