使用 awk /pattern/ { print "text"} /pattern/ {print ""} 时是否有 ELSE 模式?

使用 awk /pattern/ { print "text"} /pattern/ {print ""} 时是否有 ELSE 模式?

假设我有如下文本文件:

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

有这样的事吗?

答案1

简化方法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] 

模式 {Action} 语句的突破:

  • /R1/ { print "=>" $0;next}:表示将执行有/R1/打印动作的行。意味着 awk 语句的其余部分将被忽略,并且将查看下一行。=>next

  • /R2/{print "*" $0;next}:这意味着将执行与pattern /R2/打印操作相匹配的行。*awk处理开始时,第一个pattern {action}语句将被忽略,因为pattern /R1/对于具有/R2/.这样第二条pattern {action}语句就完成了就行了。next再次意味着我们不想再进行任何处理,awk并将适当地转到下一行。

  • 1打印所有行。当只提供 no 条件时{action},awk 默认使用 using {print}。这里的条件 is1被解释为 true,所以它总是成功。如果我们到达这一点,这是因为第一条和第二条pattern {action}语句被忽略或绕过(对于不包含/R1/and 的行/R2/),因此将对其余行执行默认打印操作。

答案2

awk实现了条件语句中常见的嫌疑。最好使用它printf来代替print您想要在比赛中完成的工作。

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

答案3

Chris Down 已经展示了如何通过在块中使用显式“if”语句来获得正则表达式的 else。您还可以通过其他一些方式获得相同的效果,尽管他的解决方案可能更好。

一种是编写第三个正则表达式,它仅匹配其他不匹配的文本,在您的情况下,这看起来像这样:

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

请注意,这使用锚定的正则表达式 - 正则表达式开头的 ^ 仅在行的开头匹配 - 您的原始模式没有这样做,这会稍微减慢匹配速度,因为它将检查一行上的所有字符而不是跳到下一行。第三种(“else”)情况将匹配以非“R”([^R])的某个字符开头的行,或者以“R”开头后跟不是“1”或“”的字符的行。 2'(R[^12])。 ^ 的两种不同含义有点令人困惑,但这个错误是很久以前就犯的,不会很快改变。

要使用互补的正则表达式,它们确实需要锚定,否则 [^R] 将匹配其后面的 1。对于像您这样非常简单的正则表达式,此方法可能很有用,但随着正则表达式变得更加复杂,此方法将变得难以管理。相反,您可以为每行使用状态变量,如下所示:

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

这会将每个新行的处理设置为零,如果它与两个正则表达式中的任何一个匹配,则设置为 1,最后,如果它仍然为零,则执行打印 $0。

相关内容