usando awk com condições de valor de coluna

108

Estou aprendendo awk com The AWK Programming Language e tenho um problema com um dos exemplos.

Se eu quisesse imprimir $ 3 se $ 2 for igual a um valor (por exemplo 1), estava usando este comando que funciona bem:

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

Mas quando substituo 1 por outro critério de pesquisa, (por exemplo findtext), o comando não funciona:

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

Ele não retorna nenhuma saída e tenho certeza de que 'findtext' existe no arquivo de entrada.

Eu também tentei isso, mas não funciona:

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

Este é meu arquivo de teste chamado 'teste' e tem 9 linhas e 8 campos, separados por espaço:

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

Aqui está o que eu fiz e o resultado:

$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

Espero ver isso, que é o $ 3 que tem "ClNonZ" em seus $ 8.

0.180467091 
0.010615711 
0.492569002

Não sei por que o comando awk não retornou nada. Alguma ideia?

user1687130
fonte
Você precisa citar o valor da string "findtext", caso contrário, é um nome de variável
evil otto
Tentei aspas duplas com "findtext", mas não funciona .. é por isso que me incomoda
user1687130
1
"Não funciona" não nos diz nada. Mostre-nos entradas exatas, código exato, saída esperada e saída real.
chepner de

Respostas:

128

Se você estiver procurando por uma string específica, coloque-a entre aspas:

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

Caso contrário, awk assumirá que é um nome de variável.

Rob Davis
fonte
Tentei fazer isso, mas não deu certo, não sei por quê. Verifiquei duas vezes com grep e o texto estava lá. :(
user1687130
1
@ user1687130, acho que você precisará nos mostrar alguns exemplos de entrada e saída esperada.
Carl Norum
1
Tem certeza de que seus dados são separados por espaço. Alguns desses espaços podem ser tabulações? Tente usar awk para ecoar um único campo. Dá a awk '{ print $8 }'você o que você esperava?
Rob Davis
1
Pode ser devido à AWKimplementação (verifique com awk --version), dê uma olhada na minha resposta, funciona em GAWKe MAWKtambém.
arutaku
Isso não funciona quando usamos aspas duplas no script awk. Likeawk "$1 == \"findtext\" {print $3}"
Thirupathi Thangavel
33

Este método usa regexp, ele deve funcionar:

awk '$2 ~ /findtext/ {print $3}' <infile>
Ell
fonte
Obrigado. Eu estava procurando uma maneira de usar o awk para encontrar regex em $ NF sem usar métodos diabólicos e grep ^^
Thibault Loison
20

Dependendo da AWKimplementação que você ==está usando está ok ou não.

Você já tentou ~? Por exemplo, se você quiser que $ 1 seja "olá":

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

^significa $ 1 inicial e $$ 1 final.

Arutaku
fonte
4
Todas as implementações do awk suportam "==" e "~".
Ed Morton
2
@EdMorton - OS X awknão conseguiu corresponder ==, mas teve sucesso ~.
jww
2
@jww Falha ao combinar o quê com o quê? São equivalentes: $1 == "hello"e $1 ~ /^hello$/. Você nunca deve fazer $1 ~ "^hello$"conforme mostrado nesta resposta, pois está usando uma string em um contexto regexp e, portanto, awk precisa converter a string em uma regexp antes de usá-la e isso tem efeitos colaterais (man awk).
Ed Morton
4

Isso é mais legível para mim

awk '{if ($2 ~ /findtext/) print $3}' <infile>
user2773013
fonte
2

Minha versão do awk é 3.1.5.

Sim, o arquivo de entrada é separado por espaço, sem guias.

De acordo com a resposta de arutaku, aqui está o que tentei que funcionou:

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


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

O que não funcionou (não sei porquê e talvez devido à minha versão awk :),

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

Obrigado a todos por suas respostas, comentários e ajuda!

user1687130
fonte
9
Isso não tem nada a ver com a sua versão do awk. Você criou seu arquivo de teste no Windows para qualquer ferramenta que você usou para fazer aquele controle-Ms anexado ao final de cada linha para que o último campo em cada linha seja ClNonZ<control-M>, não ClNonZé por isso que uma comparação de correspondência parcial RE como feita com grep ou "~ "no awk encontra, mas uma comparação de igualdade não.
Ed Morton
2
Sim, faz sentido. Eu tentei o teste $ dos2unix e então usei "==" para substituir "~" e funcionou. Obrigada pelo esclarecimento!
user1687130
-3

por favor tente isso

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

ou

echo cat filename | grep ClNonZ | awk '{print $3}';
Mustafa
fonte
Infelizmente, esta resposta não usa a sintaxe Awk que o usuário pediu especificamente!
Asfand Qazi