awk / pattern / {print“ text”} / patern / {print“”}を使用する場合、ELSEパターンはありますか?


22

次のようなテキストファイルがあるとします。

R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

awkこれらの行を別々に処理するために使用したい

awk '/R1/ { print "=>" $0} /R2/ { print "*" $0} '

また、残りのすべての行をそのまま(既に処理した行を複製せずに)印刷したいので、基本的には行の/ELSE/ { print $0}最後に必要 awkです。

そのようなことはありますか?

回答:


27

簡素化されたアプローチ awk

awk '/R1/ {print "=>" $0;next} /R2/{print "*" $0;next} 1' text.file

[jaypal:~/Temp] cat text.file 
R1 12 324 3453 36 457 4 7 8
R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242

[jaypal:~/Temp] awk '/R1/ { print "=>" $0;next} /R2/{print "*" $0;next}1' text.file
=>R1 12 324 3453 36 457 4 7 8
*R2 34 2342 2525 25 25 26 26 2 2
R3 23 2342 32 52 54 543 643 63
R4 25 234 2342 4 234242
[jaypal:~/Temp] 

パターンのブレークアウト{アクション}ステートメント:

  • /R1/ { print "=>" $0;next}:これは/R1/、印刷のアクションを持つ行が実行=>されることを意味します。nextは、awkステートメントの残りが無視され、次の行が調べられることを意味します。

  • /R2/{print "*" $0;next}:これはpattern /R2/、印刷のアクションに一致する行*が実行されることを意味します。ときにawk開始を処理し、最初のpattern {action}通りのステートメントは無視されpattern /R1/た行に対して真ではありません/R2/。したがって、2番目のpattern {action}ステートメントは行で行われます。nextこれもまた、これ以上の処理を望まないことを意味し、awk正式に次の行に進みます。

  • 1すべての行を印刷します。条件にnoを指定した{action}場合、awkはデフォルトでを使用し{print}ます。ここで条件は1trueと解釈されるため、常に成功します。この点に到達すると、最初と2番目のpattern {action}ステートメントが無視またはバイパスされたため(/R1/and を含まない行の場合/R2/)、残りの行に対してデフォルトの印刷アクションが実行されます。


投稿されたすべてのソリューションの中で最速でわずかに実行するようです。
クリスダウン

1
ここで構文糖が正しい用語であるかどうかはわかりません...それは単なる構文です。
ダニエル・ハーシュコヴィッチ

7

awk条件に関しては、通常の容疑者を実装します。試合でやりたい仕事のprintf代わりに使用することprintをお勧めします。

awk '{ if (/^R1/) { printf("=> %s\n", $0) } else if (/^R2/) { printf("* %s\n", $0) } else { print $0 } }'

if-then-elseこれは本当に必要ありません。
ジャイパルシン

1
これは完璧に機能しますが、慣用的ではありません。の賢明な使用nextは、awkプログラミングの重要なツールです。
dmckee

2
printfここで使う意味がわかりません。唯一の利点は(連結よりも手の込んだ書式設定を行っていない限り)、改行を追加しないことです。これはここでは関係ありません。
ジル 'SO-悪であるのをやめる'

1
それは直観に反した驚くべき結果です。装飾のないprint出力のみにあり$0、一方、printfフォーマット文字列を解析する必要があります。
jw013

5

Chris Downは、ブロック内で明示的な 'if'ステートメントを使用して正規表現のelseを取得する方法を既に示しました。他の方法でも同じ効果を得ることができますが、おそらく彼の解決策の方が優れています。

1つは、他のテキストと一致しないテキストのみに一致する3番目の正規表現を記述することです。この場合、これは次のようになります。

awk '/^R1/ { print "=>" $0}
     /^R2/ { print "*" $0}
     /^[^R]/ || /^R[^12]/ { print $0 } '

これはアンカーされた正規表現を使用することに注意してください-正規表現の先頭の^は行の先頭でのみ一致します-元のパターンはこれをしませんでしたが、行のすべての文字をチェックするので次の行までスキップします。3番目(「else」)の場合は、「R」ではない文字([^ R])で始まる行、または「R」で始まり「1」または「 2 '(R [^ 12])。^の2つの異なる意味はやや混乱しますが、その間違いはかなり前に行われたものであり、すぐには変更されません。

補完的な正規表現を使用するには、それらを実際に固定する必要があります。そうしないと、[^ R]が後続の1などと一致します。あなたのような非常に単純な正規表現の場合、このアプローチは有用ですが、正規表現がより複雑になると、このアプローチは管理できなくなります。代わりに、次のように各行に状態変数を使用できます。

awk '{ handled = 0 }
     /^R1/ { print "=>" $0; handled = 1}
     /^R2/ { print "*" $0; handled = 1}
     { if (!handled) print $0 } '

これは、新しい行ごとに処理をゼロに設定し、2つの正規表現のいずれかに一致する場合は1に設定し、最後に、まだゼロの場合は、印刷$ 0を実行します。


大きなファイルでは、両方とも条件付きを使用するよりも効率が悪いことに注意してください(ここに示すよう)。rfile質問者のデータセットの10000行だけが繰り返されています。
クリスダウン

4
if (!handled)うん!next他のアクションの検討を停止するために使用します。
dmckee

+1 if (!handled)。一般的で柔軟で再利用可能なソリューションが適しています。この質問がある次の人が印刷後にさらに処理を行いたい場合はどうなりますか?との答えnextはそれをサポートしていません。
スコット14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.