awk匹配列中的多个模式

Ped*_*roA 2 awk

awk匹配一列中多个模式的正确语法是什么?有一个像这样的列式文件:

c11 c21 c31
c12 c22 c32
c13 c23 c33
Run Code Online (Sandbox Code Playgroud)

如何排除第二列中与c21和c22匹配的行.

使用grep,可以执行类似的操作(但不指定仅在第二列中匹配):

> egrep -w -v "c21|c22" bar.txt 
c13 c23 c33
Run Code Online (Sandbox Code Playgroud)

我尝试玩awk但无济于事:

> awk '$2 != /c21|c22/' bar.txt 
c11 c21 c31
c12 c22 c32
c13 c23 c33

> awk '$2 != "c21" || $2 != "c22"' bar.txt 
c11 c21 c31
c12 c22 c32
c13 c23 c33
Run Code Online (Sandbox Code Playgroud)

那么,正确的awk语法是什么?

Ed *_*ton 7

$2 != /c21|c22/
Run Code Online (Sandbox Code Playgroud)

是简写

$2 != ($0 ~ /c21|c22/)
Run Code Online (Sandbox Code Playgroud)

其比较$2结果进行比较$ 0至C21或C22的,并且结果是1或0,所以它测试对于$2具有比其它的值1.

$2 != "c21" || $2 != "c22"
Run Code Online (Sandbox Code Playgroud)

正在测试$2不等于c21 $2不等于c22哪个条件始终为真.想一想 - 如果$ 2是c21那么第一个条件($2 != "c21")是假的,但是第二个条件($2 != "c22")是真的等等所以or对于任何值都是如此$2

你要写的是:

awk '$2 !~ /c21|c22/'
Run Code Online (Sandbox Code Playgroud)

或更强大:

awk '$2 !~ /^(c21|c22)$/'
Run Code Online (Sandbox Code Playgroud)

更简单(加上同样强大的)真正写出这种情况的方法是:

awk '$2 !~ /^c2[12]$/'
Run Code Online (Sandbox Code Playgroud)

如果你想做一个字符串而不是正则表达式比较那么你可以做其中任何一个如果它是一个一次性的脚本(我赞成第一个更少的否定标志,恕我直言使其更清晰):

awk '!($2 == "c21" || $2 == "c22")'
awk '$2 != "c21" && $2 != "c22"'
Run Code Online (Sandbox Code Playgroud)

而这个:

awk 'BEGIN{split("c21 c22",t); for (i in t) vals[t[i]]} !($2 in vals)'
Run Code Online (Sandbox Code Playgroud)

最后一个是最好的,因为你只指定$2一次,如果你需要测试更多,你可以只为正在拆分的字符串添加其他值,这意味着你不能在后面的脚本中破坏比较ogic.