次のファイルがあります
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
に追加する必要があるため、次の行が内容で始まることを確認するために前の行の印刷を遅らせます。)ABC
END
その後、行を2つの別々の変数にコピーし
pre
(dpre
そのうちの1つは変更されずに保持されます(後で変更せずに印刷する必要があります))、他の変数にはsub(/ {0,3}/,"END ", dpre)
文字列END
をdpre
。{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
。
- 現在の行を2つの変数に更新します
- はい;これらをしなさい
- 設定されていますか
- ファイルの終わりの
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
現在のレコードの自動印刷がオンになっているフルルックモードでは、-p
ABCまたは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ですか? - 交換を行います。ツアーでは、データを消費せずに一致する場所を主張することを理解しています。