sed:成功を条件に置き換える

sed:成功を条件に置き換える

sed私は置換を実行し、成功状態を条件として使用して行を印刷する良い使い方を見つけました。

$ seq 3 | sed -n 's/2/B/ p'
B

この短い形式を拡張してより多くのことができるかどうか疑問に思います。良い、

  • この行は、交換が成功した場合にのみ印刷されますが、
  • 印刷する前に別の作業を行う必要があります。

可能ですか?以下を試しましたが失敗しました。

$ seq 3 | sed -n 's/2/B/ {p}'
sed: -e expression #1, char 8: unknown option to `s'

答え1

/2/より複雑なコマンドのアドレスとして使用できます。

sed -n '/2/ { s/2/B/; /BB/d; p; }'

これは、少なくとも1つを含む行に対して最初の出現を2with2に置き換えてからB(この場合、この置換はs//B/「最も近い一致式を使用する」を意味する空の正規表現に短縮される可能性があります)、行を削除します。部分文字列が含まれているBB場合は、その行が出力されます(削除されていない場合)。他のラインはまったく出力されません-n

また、使用することができます

sed -e '/2/!d' -e 'other commands'

これにより、それを含まないすべての行が削除され、残りの行に2適用されます。other commands

それぞれ与えられたを使用する複数の式を使用すること-eは、入力ストリームに一連のコマンドを適用する標準的な方法ですsed。ほとんどの最新のsed実装では、区切られた式も理解しています;。 GNUを最初に見るsed必要はありません。;}

答え2

pこれはコマンドの表示であり、コマンドではsedありません。p sed

何かをするには、(p生成されたパターンスペースを印刷したりwファイルに書き込む(wコマンドで使用できる別のフラグ)に加えて)代替エントリがある場合は、コマンド(またはGNUコマンド)をs使用できます。いいえ)、特定のラベル(またはラベルがない場合は末尾)に分岐するので、次のことができます。tTsed-T

GNU固有:

sed -n 's/2/B/;T;=;p;#and other commands if there were substitutions'

良い:

substitute(the first occurrence of 2 with B in the pattern space)
if (no substitution was made so far)
   goto(end)
print-pattern-space
print-input-line-number
: end

基準:

sed '
  s/2/B/;t more
  d
  :more
  p;=;#and other commands
'

または、次のものを使用できます。

sed -n '/regexp/ { s//replacement/; p; =; }'

空の正規表現を使用すると、以前の正規表現(たとえば)が再利用されますed

答え3

「{....}」を使用してコマンドをグループ化できます。一般的な形式は次のとおりです。

/<regexp>/ {
             cmd1
             cmd2
             ...
           }

ここで、「cmd」は「s/.../.../」だけでなく、「p」、「q」などの一般的なsedコマンドです。コマンドが正規表現に一致するすべての行に適用される「ルール」と考えてください。正規表現と開き中括弧の間に感嘆符を使用してルールを否定することもできます。この場合、ルールはすべての行に適用されます。いいえ正規表現を一致させます。

以下は、スクリプトの先頭からコメントではなく最初の行まで、すべてのコメントのみの行を印刷する例です。

sed '/^[[:blank:]]*#/ !{
                          q
                        }'

「#」で始まるすべての行はルールと一致するため、印刷されます(これを抑制するために「-n」オプションを使用しませんでした)。正規表現に一致しない最初の行(実際にはすべての行ですが、実際には最初の行のみが処理されます)は、単にsedを終了するルールをトリガーします。

しかし、ルールを使用するよりも強力な別の方法があります。いわゆる「タグ」を定義することです。 GOTOなどのコマンドを使用してシンボル位置に分岐します。仕組みは次のとおりです。

1) 無条件分岐 sed スクリプトは次のように動作します。入力の最初の行を読み取り、最後のコマンドに達するまですべてのsedコマンドを順番に適用します(行が変更されると、変更された行に追加のコマンドが適用されます)。 "-n"オプションを使用しないと、結果はに印刷されます。その後、次の入力行が読み取られ、最後の入力行が処理されるまでプロセスが再開されます。

現在の行にコマンドが適用される順序を変更する方法があります。

:[ラベル]

コマンド自体は何もしませんが、別のコマンドを使用してこの場所に分岐できます。 BASICと「goto」コマンドのような言語を覚えていますか?これには、後続の「goto」(類似)コマンドが移動できるラベルが表示されます。以前に定義されたラベルに分岐する無条件sedコマンドは、次のとおりです。

b [ラベル]

「b」は「分岐」を意味する。 ":" コマンドで定義した内容に対応します。ラベルを省略すると、実行はスクリプトの最後に分岐します。

たとえば、次のようになります。私はプログラムを手に入れましたが、残念ながら、コードのインデントはスペースの代わりにタブで行われましたが、これを変更したいと思います。明らかに必要な場合があるので、コード内のタブではなくコードの前のタブだけを変更したいと思います。残念ながら、正規表現にはそのための直接的な機能がないので、直接実装する必要があります。アルゴリズムは次のとおりです。 1行が次の形式である限りスペースの後にタブ文字が続きます。最初のタブを8つのスペースに変更し、テキストの前にタブがなくなるまで同じ行で繰り返します。こうして線が印刷されます。このループ構造は、「:」および「b」コマンドを使用して設定されます。ここでは、さまざまな種類のスペースを読み取るために、\ b(スペース)と\ t(タブ)を使用しています。スクリプトをテストするときは、実際のスペース/タブに置き換えてください。

sed ':start
     /^\b*\t/ {
                s/^\(\b*\)\t/\1\b\b\b\b\b\b\b\b/
                b start
              }'

2) 条件分岐 これでタグを設定して分岐する方法がわかったので、追加の変更があります。成功する前に実行されたs / ... / ... /コマンドに基づいてそのタグに分岐できます(つまり、何かが変更されることを意味します)。あるいは何もない。これを行うコマンドは次のとおりです。

t [タグ]

次に分岐

T [タグ]

これは「t」の否定的な対応です。分岐するいいえs コマンドが成功しました。

以下は、動作方法の簡単な例です。特に役に立つ作業は行いませんが、原則を示しています。 sedスクリプトは、すべての入力の最初の行のみを受け入れます。最初の文字が「a」、「b」、または「c」のいずれかである場合は「YES」を印刷し、そうでない場合は「NO」を印刷します。

sed -n 's/^[abc]/x/
        t yes
        b no
        :no
        s/^.*$/NO/p
        q
        :yes
        s/^.*$/YES/p
        q'

制御フローは簡単です。最初に置換を試み、最初の文字が「a」、「b」、または「c」の場合は「x」に変更します。成功すると、分岐コマンド「t yes」はlael「yes」に分岐され、行全体が「YES」に変更され、sedが終了します(「q」コマンド)。この交換が失敗した場合は、「t」コマンドを渡し、「b」コマンドを実行して「no」ラベルにジャンプします。

さまざまな入力(echo "..." | sed <script>十分に良い)を試して動作を確認し、「t」コマンドを「T」に変更して結果に与える影響を確認してください。

答え4

それ以上の作業が必要な場合は、s/old/new/明確さ、堅牢性、移植性、メンテナンス性などの組み合わせのためにsedの代わりにawkを使用することをお勧めします。

$ seq 3 | awk 'sub(/2/,"B")'
B

$ seq 3 | awk 'sub(/2/,"B") { sub(/B/,"foo"); print }'
foo

関連情報