この質問に対する答えはどこにもありません。簡単に見えますが、おそらくそうではないかもしれないと思い始めました。
sedがこの文字列からSTOPの前にすべてのCATを削除するようにしたいと思います。
two CAT two four CAT CAT seven one STOP four CAT two CAT three
したがって、私が望む結果は次のとおりです。
two two four seven one STOP four CAT CAT two CAT three
文字列のどの場所にもCATがあります。停止マークはどこにあっても構いませんが、次のいずれかを使用でき、常にSTOPとしてマークされます。
(編集:以下に指摘したように、私の質問は不明です。CATには隣接する空白がなければなりませんか、それとも境界でどんな文字でも持つことができますか?英数字以外の文字しかありませんか?です。 大きな bash 関数) 単純化しすぎているので、以下の解決策は隣接関係について別の仮定を行うことができることを読者に覚えておいてください。ありがとうございます)
答え1
CAT
以前のsがなくなるまで、ループ内で一度に1つずつ置き換えることができますSTOP
。
$ echo 'two CAT two four CAT CAT seven one STOP four CAT two CAT three' |
sed -e :a -e '/CAT.*STOP/s/CAT //;ta'
two two four seven one STOP four CAT two CAT three
答え2
いくつかの奇妙な場合:
awk '{while($0~/CAT .*STOP/)sub(/CAT /,"")}1' file
$ echo 'two CAT two four CAT CAT seven one STOP four CAT two CAT three' |
awk '{while($0~/CAT .*STOP/)sub(/CAT /,"")}1'
two two four seven one STOP four CAT two CAT three
答え3
そしてperl
perl -pe 's/CAT (?=.*STOP)//g'
CAT
STOP
次の行が存在する場合にのみ置き換えられます。
答え4
(これがsedパズルよりも重要な場合は、sedを使用してまったく使用しないことをお勧めします。ここのあいまいな答えとは異なり、Pythonではこれを簡単かつ非常に明確に書くことができます。)
以下のように、sedでループを使用できます。コードの下に指示と注意事項があります。
s/STOP/@/
: loop
s/^\([^@]*\)CAT\(.*\)$/\1\2/
t loop
s/@/STOP/
p
次のように実行
$ sed -n -f t.sed
説明したように、すべての行を変更します。存在しない場合は、入力行からすべての項目を削除するようにSTOP
コードが書かれています。CAT
また、このコードはこれが@
入力行に表示されないと仮定します。その場合は、他のマーカー文字を探す必要があります。
どうしたの?コードを見てみましょう。
s/STOP/@/
存在しない項目に一致する正規表現を作成することは困難ですsed
。ただし、単一文字の場合(たとえば、操作を実行するx
場合)は例外です。[^x]*
したがって、私たちのセンチナルをSTOP
行の残りの部分で使用されていない単一の文字に置き換えてください。そのような性質がなければ、人生はさらに困難になり、これがsed
実際に作業に適したツールではないことを覚えています。
: loop
s/^\([^@]*\)CAT\(.*\)$/\1\2/
t loop
これが重要な部分です。: loop
後で再分岐できるタグをsedスクリプトで宣言してください。次に、その行で前にないタグをs///
見つけて置き換え、前後のテキストを保持します。置換が発生した場合は、戻ってもう一度やり直してください。交換が失敗した場合、つまり交換が見つからない場合、返された分岐は使用されません。CAT
@
t loop
loop
CAT
loop
s/@/STOP/
p
実際のSTOP
テキストを復元し、最後の行を印刷します。