Verwenden von awk mit Spaltenwertbedingungen

108

Ich lerne awk von der AWK-Programmiersprache und habe ein Problem mit einem der Beispiele.

Wenn ich $ 3 drucken wollte, wenn $ 2 gleich einem Wert ist (z. B. 1), habe ich diesen Befehl verwendet, der gut funktioniert:

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

Wenn ich jedoch 1 durch ein anderes Suchkriterium ersetze (z. B. findtext), funktioniert der Befehl nicht:

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

Es gibt keine Ausgabe zurück und ich bin sicher, dass 'findtext' in der Eingabedatei vorhanden ist.

Ich habe es auch versucht, aber es funktioniert nicht:

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

Hier ist meine Testdatei mit dem Namen 'test' und sie enthält 9 Zeilen und 8 Felder, die durch Leerzeichen getrennt sind:

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

Folgendes habe ich getan und die Ausgabe:

$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

Ich erwarte, dass dies die $ 3 sind, die "ClNonZ" in ihren $ 8 haben.

0.180467091 
0.010615711 
0.492569002

Ich weiß nicht, warum der Befehl awk nichts zurückgegeben hat. Irgendwelche Gedanken?

user1687130
quelle
Sie müssen den Zeichenfolgenwert "findtext" angeben, andernfalls ist es ein Variablenname
böse otto
Ich habe versucht, doppelte Anführungszeichen mit "findtext" zu setzen, aber es funktioniert nicht. Deshalb stört es mich
user1687130
1
"Funktioniert nicht" sagt uns nichts. Zeigen Sie uns genaue Eingaben, genauen Code, erwartete Ausgabe und tatsächliche Ausgabe.
Chepper

Antworten:

127

Wenn Sie nach einer bestimmten Zeichenfolge suchen, setzen Sie Anführungszeichen darum:

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

Andernfalls geht awk davon aus, dass es sich um einen Variablennamen handelt.

Rob Davis
quelle
Ich habe es versucht, aber es funktioniert nicht. Ich weiß nicht warum. Ich habe mit grep nachgesehen und der Text war da drin. :(
user1687130
1
@ user1687130, ich denke, Sie müssen uns einige Beispieleingaben und erwartete Ausgaben zeigen.
Carl Norum
1
Sind Sie sicher, dass Ihre Daten durch Leerzeichen getrennt sind? Könnten einige dieser Leerzeichen Tabulatoren sein? Versuchen Sie, mit awk ein einzelnes Feld wiederzugeben. Gibt awk '{ print $8 }'Ihnen, was Sie erwarten würden?
Rob Davis
1
Es könnte an der AWKImplementierung liegen (überprüfen Sie es mit awk --version), schauen Sie sich meine Antwort an, es funktioniert auch GAWKund MAWK.
Arutaku
Dies funktioniert nicht, wenn wir das awk-Skript in doppelte Anführungszeichen setzen. Likeawk "$1 == \"findtext\" {print $3}"
Thirupathi Thangavel
33

Diese Methode verwendet Regexp, es sollte funktionieren:

awk '$2 ~ /findtext/ {print $3}' <infile>
Ell
quelle
Vielen Dank, ich habe nach einer Möglichkeit gesucht, mit awk Regex auf $ NF zu finden, ohne diabolische Methoden und grep zu verwenden ^^
Thibault Loison
20

Abhängig von der von AWKIhnen verwendeten Implementierung ==ist dies in Ordnung oder nicht.

Hast du es versucht ~? Zum Beispiel, wenn Sie möchten, dass $ 1 "Hallo" ist:

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

^bedeutet $ 1 Start und $ist $ 1 Ende.

Arutaku
quelle
4
Alle awk-Implementierungen unterstützen sowohl "==" als auch "~".
Ed Morton
2
@EdMorton - OS X konnte awknicht übereinstimmen ==, war aber erfolgreich ~.
JWW
2
@jww Fehler beim Abgleichen von was mit was? Diese sind gleichwertig: $1 == "hello"und $1 ~ /^hello$/. Sie sollten niemals das tun $1 ~ "^hello$", was in dieser Antwort gezeigt wird, da eine Zeichenfolge in einem regulären Ausdruck verwendet wird. Daher muss awk die Zeichenfolge vor der Verwendung in eine reguläre Zeichenfolge konvertieren, was Nebenwirkungen hat (man awk).
Ed Morton
4

Das ist für mich besser lesbar

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

Meine awk-Version ist 3.1.5.

Ja, die Eingabedatei ist durch Leerzeichen getrennt, keine Registerkarten.

Nach der Antwort von Arutaku habe ich Folgendes versucht:

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


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

Was hat nicht funktioniert (ich weiß nicht warum und vielleicht aufgrund meiner awk Version :),

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

Vielen Dank für Ihre Antworten, Kommentare und Hilfe!

user1687130
quelle
9
Dies hat nichts mit Ihrer awk-Version zu tun. Sie haben Ihre Testdatei unter Windows erstellt, unabhängig davon, welches Tool Sie verwendet haben, um die angehängten Steuerelement-Ms an das Ende jeder Zeile anzuhängen, sodass das letzte Feld in jeder Zeile angezeigt wird. Dies ist ClNonZ<control-M>nicht ClNonZder Grund, warum ein RE-Teilübereinstimmungsvergleich mit grep oder "~" durchgeführt wurde "in awk findet es aber ein Gleichheitsvergleich nicht.
Ed Morton
2
Ja, mach Sinn. Ich habe $ dos2unix test ausprobiert und dann "==" verwendet, um "~" zu ersetzen, und es funktioniert. Danke für die Erklärung!
user1687130
-3

Bitte versuchen Sie dies

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

oder

echo cat filename | grep ClNonZ | awk '{print $3}';
Mustafa
quelle
Leider verwendet diese Antwort nicht die Awk-Syntax, nach der der Benutzer speziell gefragt hat!
Asfand Qazi