AWK中的条件

时间:2019-06-07 10:31:53

标签: bash awk conditional-statements

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

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

输入:

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

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

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

我得到了我期望的输出:

foo,bar
foo,bar

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

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

我得到了我没想到的输出:

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

我希望不返回任何行,这是我的目标。那是怎么回事?

这两个条件是否互相抵消?我阅读了boolean expressions的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}'

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

2 个答案:

答案 0 :(得分:3)

您要过滤掉字段2与foobar匹配的行,因此希望该字段与foo 不相等 >和 bar。因此,您需要&&运算符:

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

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

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

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

答案 1 :(得分:2)

您需要的是:

awk '$2 !~ /foo|bar/' file

给出真正的失败代码:

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

并假设您的字段确实如代码所暗示的那样用制表符分隔,您可以将其编写为:

awk -F'\t' '$5 !~ /F(iscal|Y).*Program Totals/'