использование awk с условиями значения столбца

109

Я изучаю awk на языке программирования AWK, и у меня проблема с одним из примеров.

Если бы я хотел напечатать $ 3, если $ 2 равно значению (например 1), я использовал эту команду, которая отлично работает:

awk '$2==1 {print $3}' <infile> | more

Но когда я заменяю 1 другим критерием поиска (например findtext), команда не работает:

awk '$1== findtext {print $3}' <infile> | more

Он не возвращает никаких результатов, и я уверен, что во входном файле есть «findtext».

Я тоже пробовал это, но не работает:

awk '$1== "findtext" {print $3}' <infile> | more

Вот мой тестовый файл с именем test, в нем 9 строк и 8 полей, разделенных пробелом:

1 11 0.959660297 0 0.021231423 -0.0073 -0.0031 MhZisp
2 14 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ
3 19 0.98089172 0 0 -0.0158 0.0124 MhNonZ
4 15 0.704883227 0.265392781 0.010615711 -0.0087 -0.0092 MhZisp
5 22 0.010615711 0.959660297 0.010615711 0.0476 0.0061 ClNonZ
6 23 0.715498938 0 0.265392781 -0.0013 -0.0309 Unkn
7 26 0.927813163 0 0.053078556 -0.0051 -0.0636 MhZisp
8 44 0.55626327 0.222929936 0.201698514 0.0053 -0.0438 MhZisp
9 31 0.492569002 0.350318471 0.138004246 0.0485 0.0088 ClNonZ

Вот что я сделал и результат:

$awk '$8 == "ClNonZ" {print $3}' test 

$ grep ClNonZ test 
2 14 0.180467091 0.800424628 0 0.0566 0.0103 ClNonZ
5 22 0.010615711 0.959660297 0.010615711 0.0476 0.0061 ClNonZ
9 31 0.492569002 0.350318471 0.138004246 0.0485 0.0088 ClNonZ

Я ожидаю увидеть это, то есть 3 доллара, в 8 долларов которых есть "ClNonZ".

0.180467091 
0.010615711 
0.492569002

Не знаю, почему команда awk ничего не вернула. Есть предположения?

user1687130
источник
Строковое значение нужно заключить в кавычки «findtext», иначе это имя переменной
evil otto
Я пробовал использовать двойные кавычки с "findtext", но это не сработало .. вот почему меня это беспокоит
user1687130 06
1
«Не работает» нам ничего не говорит. Покажите нам точные входные данные, точный код, ожидаемый результат и фактический результат.
chepner 06

Ответы:

130

Если вы ищете конкретную строку, заключите ее в кавычки:

awk '$1 == "findtext" {print $3}'

В противном случае awk будет считать, что это имя переменной.

Роб Дэвис
источник
Я пробовал это, но не работает, не знаю почему. Я дважды проверил с помощью grep, и текст был там. :(
user1687130 06
1
@ user1687130, я думаю, вам нужно будет показать нам несколько примеров ввода и ожидаемого результата.
Карл Норум
1
Вы уверены, что ваши данные разделены пробелами? Могут ли некоторые из этих пробелов быть вкладками? Попробуйте использовать awk для вывода одного поля. Дает awk '{ print $8 }'то, чего вы ожидаете?
Роб Дэвис
1
Это может быть связано с AWKреализацией (проверьте это awk --version), посмотрите мой ответ, он работает GAWKи MAWKтоже.
arutaku
Это не работает, когда мы используем двойные кавычки в awk-скрипте. Likeawk "$1 == \"findtext\" {print $3}"
Thirupathi Thangavel
34

Этот метод использует регулярное выражение, он должен работать:

awk '$2 ~ /findtext/ {print $3}' <infile>
Ell
источник
Спасибо, я искал способ использовать awk для поиска регулярного выражения в $ NF без использования дьявольских методов и grep ^^
Thibault Loison
20

В зависимости от того, AWKкакую реализацию вы используете, ==это нормально или нет.

Вы пробовали ~? Например, если вы хотите, чтобы $ 1 был "привет":

awk '$1 ~ /^hello$/{ print $3; }' <infile>

^означает начало в $1 доллар и конец в 1 доллар.

Arutaku
источник
4
Все реализации awk поддерживают как «==», так и «~».
Эд Мортон,
3
@EdMorton - OS X не awkудалось сопоставить ==с ~.
jww
2
@jww Не удалось сопоставить что с чем? Они эквивалентны: $1 == "hello"и $1 ~ /^hello$/. Вы никогда не должны делать то, $1 ~ "^hello$"что показано в этом ответе, поскольку он использует строку в контексте регулярного выражения, и поэтому awk должен преобразовать строку в регулярное выражение перед его использованием, и это имеет побочные эффекты (man awk).
Эд Мортон
4

Для меня это более читабельно

awk '{if ($2 ~ /findtext/) print $3}' <infile>
user2773013
источник
2

Моя версия awk - 3.1.5.

Да, входной файл разделен пробелами, без табуляции.

Согласно ответу Арутаку, вот то, что я пробовал, сработало:

awk '$8 ~ "ClNonZ"{ print $3; }' test  
0.180467091
0.010615711
0.492569002


$ awk '$8 ~ "ClNonZ" { print $3}' test  
0.180467091
0.010615711
0.492569002

Что не сработало (не знаю почему, а может быть, из-за моей awk-версии :),

$awk '$8 ~ "^ClNonZ$"{ print $3; }' test
$awk '$8 == "ClNonZ" { print $3 }' test

Спасибо всем за ответы, комментарии и помощь!

user1687130
источник
9
Это не имеет ничего общего с вашей версией awk. Вы создали свой тестовый файл в Windows, поэтому независимо от того, какой инструмент вы использовали для этого, добавлял control-M в конец каждой строки так, чтобы последнее поле в каждой строке было ClNonZ<control-M>, а не ClNonZпоэтому сравнение частичного совпадения RE, как это делается с помощью grep или "~ "в awk находит это, а сравнение на равенство - нет.
Эд Мортон
2
Да, имеет смысл. Я попробовал $ dos2unix test, а затем использовал «==» для замены «~», и он работает. Спасибо за объяснение!
user1687130 07
-3

пожалуйста, попробуйте это

echo $VAR | grep ClNonZ | awk '{print $3}';

или

echo cat filename | grep ClNonZ | awk '{print $3}';
Мустафа
источник
К сожалению, этот ответ на самом деле не использует синтаксис Awk, о котором специально просил пользователь!
Асфанд Кази