Вопрос или проблема
У меня есть файл с двумя колонками, например:
$ cat data
a4 b1
a4 c2
a4 b4
z4 c2
Я хочу сопоставить обе колонки так, чтобы
если (column1 = a4 and column2 = b1)
ИЛИ (column1 = a4 and column2 = c2)
то вывод в колонке3 должен быть
(ЖЕЛАЕМЫЙ ВЫВОД):
a4 b1 matched
a4 c2 matched
a4 b4 -
z4 c2 -
Поэтому я попытался внедрить свою логику в однострочный awk:
$ awk '{print $1, $2, (($1 = a4 && $2 = b1) || ($1 = a4 && $2 = c2) ? "a4-matched" : "-")}' data
И я получаю – для всей колонки3, я думаю, у меня синтаксическая ошибка в awk, или что-то другое отсутствует — ниже результат:
a4 b1 -
a4 c2 -
a4 b4 -
z4 c2 -
Вы были почти правы, но, похоже, вы допустили синтаксическую ошибку: $1=a4
не проверяет, равна ли первая колонка a4
, а присваивает содержимое переменной awk
a4
(которая не определена и поэтому пуста) первой колонке, перезаписывая ее содержимое (которое вы уже напечатали, так что вы этого не заметили) и также оценивается как “ложь”, потому что неинициализированная переменная оценивается как “ложь”. То же самое верно и для ваших других сравнений. Поэтому вы никогда не получаете условие “сопоставлено” как “истина”.
С (несколькими) необходимыми исправлениями программа будет выглядеть следующим образом:
awk '{if (($1=="a4" && $2=="b1") || ($1=="a4" && $2=="c2")) $3="matched"; else $3="-"} 1' data.txt
Она работает следующим образом:
- Для каждой строки она проверяет, соблюдаются ли условия, которые вы упоминаете, и добавляет третью колонку в строку, устанавливая
$3
либо в-
, либо вmatched
. - Затем она печатает текущую строку, включая любые внесенные изменения. Это значение по-видимому, бесполезного
1
вне блока правил –awk
печатает текущую строку, включая все предыдущие изменения, если он встречает условие, которое оценивается как “истина” вне правила.
Обратите внимание, что приведенная выше программа написана явно для удобства понимания и для демонстрации этого момента. В вашем случае ее можно сократить, так как условие на $1
одинаково для обоих “разрешенных” случаев $2
:
awk '{if ($1=="a4" && ($2=="b1" || $2=="c2")) $3="matched"; else $3="-"} 1' data.txt
Также обратите внимание, что изменение любого поля приведет к восстановлению awk
строки из ее отдельных полей с использованием разделителя полей вывода (по умолчанию один пробел), поэтому, если исходные поля были разделены более чем одним пробелом, оригинальное форматирование будет испорчено. Если это проблема, вы должны использовать стратегию “добавления”, которую вы уже выбрали в попытке, хотя вы должны тогда печатать $0, ( ваша условная строка )
, а не $1, $2, ( ваша условная строка )
.
$ awk '{print $0, ($1=="a4" && ($2 ~ /^(b1|c2)$/) ? "matched" : "-")}' file
a4 b1 matched
a4 c2 matched
a4 b4 -
z4 c2 -
Вам не нужно дважды проверять $1
, проверьте его один раз, так как это одно и то же условие в обоих случаях, и сделайте несколько проверок $2
для различных вариантов. Обратите внимание, что присвоение новых полей приведет к перестройке $0
с использованием значения по умолчанию OFS
(один пробел), что приведет к сжатию последовательных пробелов в один, если в вашем входе были такие.
awk '{ print $0, ($1=="a4" && ($2=="b1" || $2=="c2")?"matched":"-") }' infile
Вы также можете просто использовать оператор сравнения меньше (<
) вместо логических, таких как ИЛИ (||)
/ И (&&)
, как только вы отменили одно из условий, так как вы на самом деле не экономите столько времени, используя короткое замыкание для относительно простых логических выражений:
echo 'a4 b1
a4 c2
a4 b4
z4 c2' |
awk '$3 = ($2 !~ /^(b1|c2)$/) < ($1 == "a4") ? "matched" : "-"'
a4 b1 matched
a4 c2 matched
a4 b4 -
z4 c2 -
Ответ или решение
Использование операторов AND и OR в программах на awk
Программирование с использованием языка awk позволяет эффективно обрабатывать текстовые данные и проводить анализ файлов. В этой статье мы обсудим, как применять логические операторы AND (&&) и OR (||) в awk для выполнения сложных условий, на примере обработки двухколоночного файла данных.
Пример данных
Предположим, у нас есть следующий файл с именем data.txt
:
a4 b1
a4 c2
a4 b4
z4 c2
Задача
Наша цель состоит в том, чтобы сопоставить данные из двух колонок, при этом:
- Если
column1
=a4
иcolumn2
=b1
- ИЛИ
column1
=a4
иcolumn2
=c2
то в третьей колонке мы хотим видеть "matched". В противном случае — знак "минус" (-
).
Ошибка в первоначальном коде
В вашем первоначальном коде присутствует синтаксическая ошибка. Вы используете оператор присваивания (=
) вместо оператора сравнения (==
). Примером корректного кода может служить следующее:
awk '{print $1, $2, (($1 == "a4" && $2 == "b1") || ($1 == "a4" && $2 == "c2") ? "matched" : "-")}' data.txt
Однако, как вам уже указали, можно значительно упростить условия, так как условие на column1
одинаково для обоих случаев:
Оптимизированный код
Учитывая, что мы проверяем одно и то же значение в первой колонке, мы можем оптимизировать код, используя:
awk '{print $0, ($1 == "a4" && ($2 == "b1" || $2 == "c2") ? "matched" : "-")}' data.txt
Объяснение кода
-
Проверка условий: Мы сначала проверяем, равно ли значение первого столбца
a4
. Затем с помощью оператора OR проверяем, равен ли второй столбецb1
илиc2
. -
Использование тернарного оператора: Если оба условия истинны, то присваиваем третьему столбцу строку
matched
; в противном случае –-
. -
Печать строки:
print $0
печатает всю исходную строку, а также добавляет результат проверки условий в новую колонку.
Результат выполнения
После выполнения указанного кода, вы получите следующий вывод:
a4 b1 matched
a4 c2 matched
a4 b4 -
z4 c2 -
Дополнительные советы
- Если необходимо сохранить исходный формат файла, генерация новой строки с использованием метода
print
позволяет избежать потери пробелов и особенностей форматирования. - Для более сложных условий полезно использовать регулярные выражения с оператором
~
, что также можно применять к вашему примеру.
Заключение
Использование операторов AND и OR в awk позволяет непринужденно обрабатывать условия и создавать нужные нам выводы. Мы обсудили, как правильно реализовать логику сравнения и вывода результатов, а также как избежать распространенных ошибок синтаксиса. Надеюсь, это руководство поможет вам эффективно решать задачи в awk.