首页 > 解决方案 > AWK 中的条件

问题描述

我正在使用awk(MacOS 上的版本 20070501)过滤一些数据,但在将多个否定匹配条件应用于特定列中的值时遇到了语法挑战。

这是一个我认为可以解决我的问题的通用示例。

输入:

foo,bar
bar,foo
foo,bar
bar,foo

foo使用此代码,我删除了第 2 列中的匹配项:

awk 'BEGIN { FS=OFS="," } ; { if ($2 !~ /foo/ ) print $0}'

我得到了这个输出,这是我所期望的:

foo,bar
foo,bar

接下来,我在语句中添加一个附加条件,以同时删除第 2 列中if匹配的所有值:bar

awk 'BEGIN { FS=OFS="," } ; { if ($2 !~ /foo/ || $2 !~ /bar/) print $0}'

我得到了这个输出,这是我没想到的:

foo,bar
bar,foo
foo,bar
bar,foo

我预计不会返回任何行,这是我的目标。发生什么了?

这两个条件是否相互抵消?我阅读了布尔表达式的 GNU awk 文档,其中指出:

'&&' 和 '||' 运算符因其工作方式而被称为短路运算符。如果结果可以在其评估的中途确定,则对完整表达式的评估是“短路的”。

从这个片段中,我不确定如何取得进展。还是语法不正确的问题?或两者?

更新:

在@wiktor-stribiżew 的评论和帮助之后,这里更好地表示了这个问题:

1   2   3   4   5
foo bar foo bar FY 2008 Program Totals
foo bar foo bar FY 2009 Program Totals
foo bar foo bar Fiscal Year 2010 Program Totals
foo bar foo bar Fiscal Year 2011 Program Totals
foo bar foo bar Fiscal Year 2012 Program Totals
foo bar foo bar Fiscal Year 2013 Program Totals
foo bar foo bar Fiscal Year 2014 Program Totals
foo bar foo bar Fiscal Year 2015 Program Totals
foo bar foo bar Fiscal Year 2016 Program Totals
foo bar foo bar Fiscal Year 2017 Program Totals

我失败的代码是:

awk 'BEGIN { FS=OFS="\t" } ; { if ($5 !~ /Fiscal.*Program Totals/ || $5 !~ /FY.*Program Totals/) print $0}'

下面接受的答案解决了这个问题。

标签: bashawkconditional-statements

解决方案


您想过滤掉字段 2 与fooor匹配的行bar,因此您希望该字段不等于foo and bar。因此,您需要&&运算符:

awk -F',' '$2 !~ /foo/ && $2 !~ /bar/' file > newfile
#                      ^^

||请注意,如果您对条件进行分组并否定结果,您也可以使用:

awk -F\, '!($2 ~ /foo/ || $2 ~ /bar/)' file > newfile

请注意,您不需要设置OFS,因为您只打印$0(整行)并且由于它是默认操作,如果您编写如上所示的条件,则无需指定。


推荐阅读