utilisation de awk avec des conditions de valeur de colonne

109

J'apprends awk du langage de programmation AWK et j'ai un problème avec l'un des exemples.

Si je voulais imprimer 3 $ si 2 $ est égal à une valeur (par exemple 1), j'utilisais cette commande qui fonctionne bien:

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

Mais lorsque je remplace 1 par un autre critère de recherche, (par exemple findtext), la commande ne fonctionne pas:

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

Il ne renvoie aucune sortie et je suis sûr que «findtext» existe sur le fichier d'entrée.

J'ai aussi essayé ceci, mais cela ne fonctionne pas:

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

Voici mon fichier de test nommé `` test '' et il comporte 9 lignes et 8 champs, séparés par un espace:

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

Voici ce que j'ai fait et le résultat:

$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

Je m'attends à voir ce qui est le 3 $ qui a "ClNonZ" dans leur 8 $.

0.180467091 
0.010615711 
0.492569002

Je ne sais pas pourquoi la commande awk n'a rien renvoyé. Des pensées?

user1687130
la source
Vous devez citer la valeur de chaîne "findtext", sinon c'est un nom de variable
evil otto
J'ai essayé des guillemets doubles avec "findtext", mais cela ne fonctionne pas .. c'est pourquoi cela me dérange
user1687130
1
«Ça ne marche pas» ne nous dit rien. Montrez-nous les entrées exactes, le code exact, la sortie attendue et la sortie réelle.
chepner

Réponses:

128

Si vous recherchez une chaîne en particulier, mettez des guillemets autour d'elle:

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

Sinon, awk supposera que c'est un nom de variable.

Rob Davis
la source
J'ai essayé ça mais ça ne marche pas, je ne sais pas pourquoi. J'ai vérifié avec grep et le texte était là. :(
user1687130
1
@ user1687130, je pense que vous allez devoir nous montrer un exemple d'entrée et de sortie attendue.
Carl Norum
1
Êtes-vous sûr que vos données sont séparées par des espaces. Certains de ces espaces pourraient-ils être des onglets? Essayez d'utiliser awk pour faire écho à un seul champ. Ne awk '{ print $8 }'vous donner ce que vous attendez?
Rob Davis
1
Cela pourrait être dû à la AWKmise en œuvre (vérifiez-le avec awk --version), jetez un œil à ma réponse, cela fonctionne GAWKet MAWKaussi.
arutaku
Cela ne fonctionne pas lorsque nous utilisons des guillemets doubles autour du script awk. Likeawk "$1 == \"findtext\" {print $3}"
Thirupathi Thangavel
34

Cette méthode utilise regexp, cela devrait fonctionner:

awk '$2 ~ /findtext/ {print $3}' <infile>
Aune
la source
Merci, je cherchais un moyen d'utiliser awk pour trouver des regex sur $ NF sans utiliser de méthodes diaboliques et grep ^^
Thibault Loison
20

Selon l' AWKimplémentation que vous utilisez, ==c'est correct ou non.

Avez-vous essayé ~?. Par exemple, si vous voulez que $ 1 soit "bonjour":

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

^signifie 1 $ de début et $1 $ de fin.

arutaku
la source
4
Toutes les implémentations awk prennent en charge à la fois "==" et "~".
Ed Morton
2
@EdMorton - OS X awkn'a pas réussi à correspondre avec ==, mais a réussi avec ~.
jww
2
@jww Impossible de faire correspondre quoi avec quoi? Ceux-ci sont équivalents: $1 == "hello"et $1 ~ /^hello$/. Vous ne devriez jamais faire $1 ~ "^hello$"comme indiqué dans cette réponse car il utilise une chaîne dans un contexte de regexp et donc awk doit convertir la chaîne en une expression régulière avant de l'utiliser et cela a des effets secondaires (man awk).
Ed Morton
4

C'est plus lisible pour moi

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

Ma version awk est 3.1.5.

Oui, le fichier d'entrée est séparé par des espaces, pas de tabulations.

Selon la réponse d'arutaku, voici ce que j'ai essayé qui a fonctionné:

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


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

Ce qui n'a pas fonctionné (je ne sais pas pourquoi et peut-être à cause de ma version awk :),

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

Merci à tous pour vos réponses, commentaires et aide!

user1687130
la source
9
Cela n'a rien à voir avec votre version awk. Vous avez créé votre fichier de test sous Windows, donc quel que soit l'outil que vous avez utilisé pour faire ce contrôle-Ms ajouté à la fin de chaque ligne, le dernier champ de chaque ligne est ClNonZ<control-M>, ClNonZce n'est pas pourquoi une comparaison de correspondance partielle RE comme effectuée avec grep ou "~ "dans awk le trouve mais pas une comparaison d'égalité.
Ed Morton
2
Oui, ça a du sens. J'ai essayé le test $ dos2unix, puis j'ai utilisé "==" pour remplacer "~" et cela fonctionne. Merci pour l'explication!
user1687130
-3

essayez ceci

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

ou

echo cat filename | grep ClNonZ | awk '{print $3}';
Mustafa
la source
Malheureusement, cette réponse n'utilise pas réellement la syntaxe Awk que l'utilisateur a spécifiquement demandée!
Asfand Qazi