Условия в AWK - PullRequest
       45

Условия в AWK

3 голосов
/ 07 июня 2019

Я фильтрую некоторые данные с помощью awk (версия 20070501, в MacOS), но у меня возникла проблема с синтаксисом при применении нескольких условий отрицательного соответствия к значениям в определенном столбце.

Вот общий пример, которыйЯ думаю, что захватывает мою проблему.

Ввод:

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

С этим кодом я удаляю совпадения для foo в столбце 2:

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

Я получаю вывод, который я ожидал:

foo,bar
foo,bar

Затем я добавляю дополнительное условие к оператору if, чтобы также удалить все значения, соответствующие bar в столбце 2:

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

Myошибочный код будет:

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

Принятый ответ ниже разрешает это.

Ответы [ 2 ]

3 голосов
/ 07 июня 2019

Вы хотите отфильтровать строки, где поле 2 соответствует либо foo, либо bar, поэтому вы хотите, чтобы это поле было , не равным - foo и bar.Таким образом, вам нужен оператор &&:

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

Обратите внимание, что вы также можете использовать ||, если вы группируете условия и отрицаете результат:

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

Примечание вам не нужно устанавливатьOFS потому что вы печатаете только $0 (целые строки) и поскольку это действие по умолчанию, вам не нужно указывать это, если вы пишете условие, как показано выше.

2 голосов
/ 07 июня 2019

Все, что вам нужно, это:

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/'
...