指定された文字列が見つかった場合、行を修正します。

指定された文字列が見つかった場合、行を修正します。

次のファイルがあります

ABC
     2   3   4
     7   9   4
     1   2   5
ABC
     13  11  17
     2   1   1
ABC
     7   9   14
     5   8   2
     9   9   9
     7   1   2

各「ABC」値の末尾に「END」という単語を印刷したいので、ファイルは次のようになります。

ABC
     2   3   4
     7   9   4
END  1   2   5
ABC
     13  11  17
END  2   1   1
ABC
     7   9   14
     5   8   2
     9   9   9
END  7   1   2

多くの努力をしましたが、何の効果もありませんでした。誰でも助けることができますか?

答え1

awk '/^ABC/ && pre { print dpre ORS $0; pre=""; next }
                   { if(pre) print pre; pre=dpre=$0; sub(/ {0,4}/, "END ", dpre) }
END{ if(pre) print dpre }' infile

最初のブロックは、行が次に始まる場合にのみ実行されます。ABC 文字列と一時変数preまた設定されます。それ以外の場合は、次のブロックが実行されます。

このEND{...}ブロックは、すべてのジョブが完了した後に一度だけ実行されます。

もちろん、最初の行はまだpre変数がまだ設定されていないので、次のような2番目のブロックが実行されます。

  • 内容があればpreまず印刷します。 (これを行うと、その行の前if(pre) print preに追加する必要があるため、次の行が内容で始まることを確認するために前の行の印刷を遅らせます。)ABCEND

  • その後、行を2つの別々の変数にコピーしpredpreそのうちの1つは変更されずに保持されます(後で変更せずに印刷する必要があります))、他の変数にはsub(/ {0,3}/,"END ", dpre)文字列ENDdpre

    {0,4}(0または最大4つのスペース、4はの長さから取得されますEND<SPC>)を使用すると、END文字列が常に先頭に追加され、スペースがまったくない場合に元の行値が切り捨てられるのを防ぐことができます。


理解を助けるために、以下のコマンドの各繰り返しを追跡できます。

  • 繰り返す
  • 一行をお読みください。ABC/^ABC/)?
    • いいえ;何もしないと、次のブロックが実行されます。第二作品
    • はい;設定されていますかpre
      • はいその後、次の作業を行います。
        • 変数の内容dpre、単一の改行文字ORS、現在の行自体を印刷します。
        • 変数を空にしてpre=""次にジャンプ繰り返すなぜなら、next声明がそれを教えてくれるからです。
      • いいえ;何もしないと、次のブロックが実行されます。第二作品
  • 第二作品
    • 設定されていますかpre
      • はい;これらをしなさい
        • 印刷設定は「」preにあります。if(pre) print pre
        • 現在の行を2つの変数に更新しますpre=dpre=$0
        • プレフィックスENDひもdpre
      • いいえ;これらをしなさい
        • 現在の行を2つの変数に更新しますpre=dpre=$0
        • プレフィックスENDひもdpre
  • ファイルの終わりのdpre場合、変数が設定されている場合は最終ステータスを印刷します。繰り返す
  • 終わる

答え2

$ cat tst.awk
NF == 1 { sub(/^   /,"END",prev) }
NR > 1 { print prev }
{ prev = $0 }
END { sub(/^   /,"END",prev); print prev }

$ awk -f tst.awk file
ABC
     2   3   4
     7   9   4
END  1   2   5
ABC
     13  11  17
END  2   1   1
ABC
     7   9   14
     5   8   2
     9   9   9
END  7   1   2

答え3

POSIX sedパターンスペース自動印刷オフ(-n

sed -ne '
  /ABC/!{x;1!p;$!d;}
  x;1!s/^ \{0,3\}/END&/p
  ${x;/ABC/p;}
'  file
ABC
     2   3   4
     7   9   4
END  1   2   5
ABC
     13  11  17
END  2   1   1
ABC
     7   9   14
     5   8   2
     9   9   9
END  7   1   2   

上記のsedコードを展開してコメントアウトしてください。

sed -ne '
  # if we see a non boundary line...
  /ABC/!{
    x;           # store it n retrieve prev line
    1!p;         # print the prev line if not first (obviously)
    $!d;         # printed prev so go back n read next line unless we are @eof(for which see below...)
  }
  x;                  # retrieve prev
  1!s/^ \{0,3\}/END&/p; # add marker
  ${x;/ABC/p;}
  # To account for a trailing ABC
'  file

答え4

真珠この状況で使用でき、強力な正規表現機能のおかげで、実際の行に並べ替えることができます。

perl-0777現在のレコードの自動印刷がオンになっているフルルックモードでは、-pABCまたはeof行の後のすべての行を確認します。どちらの場合も、文字列「END」が先頭に挿入され、最大3つの空白文字が含まれます。

perl -0777pe '
  s/^(?!ABC)\h{0,3}(?=.*\n(?:ABC|\z))/END/mg;
' file

正規表現研究:

  • ABCで始まらない行を探す^(?!ABC)
  • 最初はスペースが3つ以上でなければなりません(最小)。\h{0,3}
  • この有利な点で現在の行の終わりを見ることができ、(?=.*\n(?:ABC|\z)そこからABCで始まる次の行を見ることができますか、それともeofですか?
  • 交換を行います。ツアーでは、データを消費せずに一致する場所を主張することを理解しています。

関連情報