sed を使用して、2 つの文字列のすべての項目を完全に置き換えます。

sed を使用して、2 つの文字列のすべての項目を完全に置き換えます。

StringAとStringBを複数回含むファイルがあるとしましょう。すべてのStringA項目をStringBに置き換え(同時に)、すべてのStringB項目をStringAに置き換えたいと思います。

今私は次のことをしています

cat file.txt | sed 's/StringB/StringC/g' | sed 's/StringA/StringB/g' | sed 's/StringC/StringA/g'

このアプローチの問題は、StringCがファイルにないと仮定することです。実際にはこれは問題ではありませんが、このソリューションはまだ厄介な感じです。つまり、UNIXの魔法をもっと学ぶ機会のように感じられます。 :)

答え1

StringBと同じ入力行に表示できない場合は、StringAsedに一方向の置換を実行し、最初の検索文字列が発生しない場合にのみ別の方法を試すように指示できます。

<file.txt sed -e 's/StringA/StringB/g' -e t -e 's/StringB/StringA/g'

一般的に、sedには簡単な方法はないと思います。但し、指定は とStringA重複することができる場合あいまいです。StringBこれは文字列の左端の項目を置き換えてから繰り返すPerlソリューションです。

<file.txt perl -pe 'BEGIN {%r = ("StringA" => "StringB", "StringB" => "StringA")}
                    s/(StringA|StringB)/$r{$1}/ge'

POSIXツールを引き続き使用するには、awkが最善の選択です。 Awkには一般的なパラメータ置換のための基本的な要素がないので、自分で開発する必要があります。

<file.txt awk '{
    while (match($0, /StringA|StringB/)) {
        printf "%s", substr($0, 1, RSTART-1);
        $0 = substr($0, RSTART);
        printf "%s", /^StringA/ ? "StringB" : "StringA";
        $0 = substr($0, 1+RLENGTH)
    }
    print
}'

答え2

今同様の作業をしています

このアプローチの問題は、StringCがファイルにないと仮定することです。

私はあなたのアプローチが良いと思います。文字列の代わりに(パターンスペースで)1行には表示されない他のものを使用する必要があります。最高の候補は\nエリーンです。
通常、パターン空間の入力行にはこの文字は含まれていないため、ファイル内のすべての合計THISの発生を置き換えるには、次のようにします。THAT

sed 's/THIS/\
/g
s/THAT/THIS/g
s/\n/THAT/g' infile

またはsedが\nRHSもサポートしている場合:

sed 's/THIS/\n/g;s/THAT/THIS/g;s/\n/THAT/g' infile

答え3

「nonce」文字列を使用して2つの単語を置き換えるのは完全に妥当だと思います。より一般的な解決策が必要な場合は、次のようにすることができます。

sed 's/_/__/g; s/you/x_x/g; s/me/you/g; s/x_x/me/g; s/__/_/g' <<<"say you say me"

これは

say me say you

x_x"x_x"文字列がある場合、置換を避けるためにここに2つの追加置換が必要です。しかし、それにもかかわらず、awkそれはまだ私にとって解決策よりも単純に見えます。

答え4

私はこれがずっと前の仕事であることを知っていますが、場合によっては次のものを使用できます。

echo foobar | sed -e 's/bar/foo/' -e 's/foo/bar/'

これは、最初の項目の最初の項目を置き換えてから最初の項目をbar置き換え、foo2番目の項目はfoo変更されないために機能します。これは、発生順序を一度だけ知っていると仮定します。

より不可知的なバージョンは次のとおりです。

echo foobar | sed 's/foo/tmp/g' | sed -e 's/bar/foo/g' -e 's/tmp/bar/g'
$ echo barbarfoobar | sed 's/foo/tmp/g' | sed -e 's/bar/foo/g' -e 's/tmp/bar/g'
foofoobarfoo

関連情報