次のsed式があります。
echo 'abcabcabc' | sed -n ':-A s/a/x/1; s/a/&/2;t-A; p'
最後の項目を除くすべての項目と'a'
交換する必要があるとします'x'
。したがって、予想される結果は次のとおりです。
xbcxbcabc
ただし、実際の出力は次のようになります。
xbcxbcxbc
すべて'a'
次へ交換'x'
私はすでに、次のような質問があることを知っています。 各行の最後の文字を除くすべての文字を置き換える
しかし、ここではsed条件分岐を使用して別のアプローチを試しています。
私自身の理解を使って私のsed表現を分析しましょう。
最初のものはsed式です。
echo 'abcabcabc' | sed -n ':-A s/a/x/1; s/a/&/2;t-A; p'
abcabcabc
sed を使用してパターン空間にインポートします。
次にラベルを設定します。:-A
次に、s/a/x/1;
最初の項目'a'
を'x'
。これで、パターン空間には以下が含まれます。xbcabcabc
s/a/&/2;
パターンスペースに両方が含まれていることを確認して、両方をそれ自体に置き換えます'a'
。したがって、パターン空間は依然として次のものを含む。'a'
&
xbcabcabc
t-A
最近の交換が成功したため、ラベルに戻ります。-A
タグから始めて-A
これをやり直し、s/a/x/1;
パターンスペースの内容をこれからxbcabcabc
これに変更します。xbcxbcabc
s/a/&/2
2つ以上があることを確認してください'a'
。今回はパターンスペースにこれが含まれていますが、xbcxbcabc
2つはないため、'a'
置換は失敗します。
t-A
なぜなら、最近交換したのは失敗する、ラベルにジャンプしてはいけませんが、パターンスペースの内容を印刷し続け、終了する必要があり-A
ます。しかし、代わりに交換が行われてもp
xbcxbcabc
失敗するもう一度タグに戻り、-A
残りの部分を'a'
置き換えます'x'
。だから結果はこれですxbcxbcxbc
l
式の間に挿入する場合:
echo 'abcabcabc' | sed -n ':-A s/a/x/1; l; s/a/&/2;t-A; p'
出力:
xbcabcabc$
xbcxbcabc$
xbcxbcxbc$
xbcxbcxbc$
xbcxbcxbc
パターン空間にこれが含まれていても、再分岐することがわかります。xbcxbcabc
それでは、私がここで何を見逃しているのでしょうか?
答え1
s/a/&/2
2番目のものをそれ自体で置き換えることに注意してくださいa
。 。a
言い換えれば、常に(最初のものを次に置き換える)と同じですs/a/x/1
。これは質問とは関係ありませんが、まだ他の状況であなたを悩ませる可能性がある誤解です。s/a/x/
a
x
GNUマニュアルによれば、t
最後の入力ラインを読んだ後に成功した置換が発生した場合、コマンドは分岐しますt
。ただし、それ以降に他のコマンドがトリガされない限りは次のとおりです。sed
t label
s///
最後の入力行を読んだ後、aが正常に置き換えられた場合に分岐し、最後またはcommandを省略するとスクリプトの最後に分岐します。t
T
label
label
同じコマンドのPOSIX仕様これに同意します。
[2addr]t [label]
テスト。最後の入力行を読み取りまたは:
実行しlabel
た後に置換が行われたかどうかを使用して、コマンド動詞に分岐しますt
。指定しない場合は、label
スクリプトの最後に分岐します。
要約すると、単一の入力行に対してコマンドが成功すると、最後のコマンド以降はs
常に指定されたラベルに分岐しますt
。t
あなたのデータは最初に変換され、次に変換さxbcabcabc
れますxbcxbcabc
。この結果が得られると、s
反復の最初のコマンドは最初のコマンドをa
に正常に置き換えるため、コマンドブランチがx
として指定されます。t
xbcxbcxbc
この問題を解決する1つの方法は、追加のt
コマンドとダミーラベルを挿入することです。
echo abcabcabc |
sed -e :A -e 's/a/x/' -e tB \
-e :B -e 's/a/&/2' -e tA
tB
最初のコマンドの「リセット成功フラグ」を実行しますs
。
答え2
簡単に保ち、代わりにawkを使用するのはどうですか?たとえば、GNU awkでは、3番目のパラメータを次のように設定しますmatch()
。
$ echo 'abcabcabc' |
awk '{match($0,/(.*)(a.*)/,t); gsub(/a/,"x",t[1]); print t[1] t[2]}'
xbcxbcabc
または awk を使用してください。
$ echo 'abcabcabc' |
awk '{match($0,/.*a/); t=substr($0,1,RLENGTH-1); gsub(/a/,"x",t); print t substr($0,RLENGTH)}'
xbcxbcabc
s、g、p(-nを含む)以外のsed構成の使用を検討するたびに、awkポータブルソリューションを使用すると、よりクリーンでシンプルで効率的で強力で、より良いソリューションがほぼ確実になることに注意してください。
答え3
テキストを反転し、2 を end に置き換え、再び反転できます。
$ echo 'abcabcabc' | rev | sed 's/a/x/2g' | rev
xbcxbcabc
sedの再帰機能を使用して練習を行わない限り、この単純なケースではラベルとループは必要ありません。