当使用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

有这样的事吗?

Answers:


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] 

模式{Action}语句的突破:

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

  • /R2/{print "*" $0;next}:这意味着将完成pattern /R2/与打印操作相符的*行。当awk处理开始时,第一条pattern {action}语句将被忽略,因为pattern /R1/对于具有的行,则将不是true /R2/。因此,第二条pattern {action}语句就可以了。next再次表示我们不希望再进行任何处理,awk将适当地转到下一行。

  • 1打印所有行。如果仅提供一个条件而没有{action},则awk默认使用{print}。在此条件被1解释为真,因此它总是成功。如果到了这一点,那是因为第一和第二条pattern {action}语句被忽略或绕过(对于不包含/R1/和的行/R2/),因此将对其余行执行默认的打印操作。


似乎在所有发布的解决方案中以最快的速度运行。
克里斯·

1
我不确定语法糖在这里是否正确……只是语法。
Daniel Hershcovich 2011年

7

awk在涉及条件时实施通常的怀疑。最好使用printf而不是print要在比赛中完成的工作。

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

您真的不需要if-then-else这个。
jaypal singh

1
尽管这很好用,但这不是惯用的。明智地使用next是awk编程中的重要工具。
dmckee

2
我不明白在printf这里使用的意义。它的唯一优点(除非您要进行比串联更高级的格式化)是它没有添加换行符,这在此不相关。
吉尔(Gilles)'所以

1
这是违反直觉和令人惊讶的结果。未经修饰的print仅需输出,$0printf必须解析格式字符串。
2012年

5

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。


应当指出的是,在大文件均大于使用条件语句(如效率较低这里)。rfile在发问者的数据集中重复了10000行。
克里斯·

4
if (!handled)!使用next停止考虑其他行动。
dmckee

为+1 if (!handled)。通用,灵活,可重用的解决方案是好的。如果下一个有此问题的人想要在打印后进行更多处理怎么办?答案next不支持。
斯科特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.