używając awk z warunkami wartości kolumn

109

Uczę się awk z języka programowania AWK i mam problem z jednym z przykładów.

Gdybym chciał wydrukować 3 $, jeśli 2 $ jest równe wartości (np. 1), Użyłem tego polecenia, które działa dobrze:

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

Ale kiedy zastępuję 1 innym kryterium wyszukiwania (np. findtext), Polecenie nie działa:

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

Nie zwraca żadnych danych wyjściowych i jestem pewien, że w pliku wejściowym istnieje element „findtext”.

Też próbowałem, ale to nie działa:

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

Oto mój plik testowy o nazwie „test”, który ma 9 linii i 8 pól oddzielonych spacją:

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

Oto, co zrobiłem i wynik:

$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

Spodziewam się, że to jest 3 $, które ma „ClNonZ” w 8 $.

0.180467091 
0.010615711 
0.492569002

Nie wiem, dlaczego polecenie awk nic nie zwróciło. jakieś pomysły?

user1687130
źródło
Musisz zacytować wartość ciągu „findtext”, w przeciwnym razie jest to nazwa zmiennej
evil otto
Próbowałem podwójnych cudzysłowów z "findtext", ale to nie działa .. dlatego to mi przeszkadza
user1687130
1
„Nie działa” nic nam nie mówi. Pokaż nam dokładne dane wejściowe, dokładny kod, oczekiwane dane wyjściowe i rzeczywiste dane wyjściowe.
chepner

Odpowiedzi:

129

Jeśli szukasz określonego ciągu, umieść go w cudzysłowie:

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

W przeciwnym razie awk przyjmie, że jest to nazwa zmiennej.

Rob Davis
źródło
Próbowałem tego, ale to nie działa, nie wiem dlaczego. Dwukrotnie sprawdziłem z grep i tekst tam był. :(
user1687130
1
@ user1687130, myślę, że będziesz musiał pokazać nam przykładowe dane wejściowe i oczekiwane wyniki.
Carl Norum
1
Czy na pewno Twoje dane są oddzielone spacjami. Czy niektóre z tych spacji mogą być tabulatorami? Spróbuj użyć awk, aby wywołać echo pojedynczego pola. Czy awk '{ print $8 }'daje Ci to, czego można się spodziewać?
Rob Davis,
1
Może to być spowodowane AWKimplementacją (sprawdź to awk --version), spójrz na moją odpowiedź, to działa GAWKi MAWKteż.
arutaku
To nie działa, gdy używamy podwójnych cudzysłowów wokół skryptu awk. Na przykładawk "$1 == \"findtext\" {print $3}"
Thirupathi Thangavel
34

Ta metoda używa wyrażenia regularnego, powinna działać:

awk '$2 ~ /findtext/ {print $3}' <infile>
Łokieć
źródło
Dzięki Szukałem sposobu na użycie awk do znalezienia wyrażenia regularnego na $ NF bez używania diabolicznych metod i grep ^^
Thibault Loison.
20

W zależności od AWKimplementacji, której używasz, ==jest w porządku lub nie.

Czy próbowałeś ~? Na przykład, jeśli chcesz, aby $ 1 oznaczało „cześć”:

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

^oznacza 1 $ początek i $1 $ koniec.

arutaku
źródło
4
Wszystkie implementacje awk obsługują zarówno „==”, jak i „~”.
Ed Morton,
2
@EdMorton - OS X awknie pasował do ==, ale udało się ~.
jww
2
@jww Nie udało się dopasować do czego? Są to równoważne: $1 == "hello"i $1 ~ /^hello$/. Nigdy nie powinieneś robić tego, $1 ~ "^hello$"co pokazano w tej odpowiedzi, ponieważ używa ona łańcucha w kontekście wyrażenia regularnego, a zatem awk musi przekonwertować ten łańcuch na wyrażenie regularne przed jego użyciem, co ma efekty uboczne (man awk).
Ed Morton
4

To jest dla mnie bardziej czytelne

awk '{if ($2 ~ /findtext/) print $3}' <infile>
user2773013
źródło
2

Moja wersja awk to 3.1.5.

Tak, plik wejściowy jest oddzielony spacjami, bez tabulatorów.

Zgodnie z odpowiedzią arutaku, oto co wypróbowałem, co zadziałało:

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


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

Co nie zadziałało (nie wiem dlaczego i może z powodu mojej wersji awk :),

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

Dziękuję wszystkim za odpowiedzi, komentarze i pomoc!

user1687130
źródło
9
Nie ma to nic wspólnego z twoją wersją awk. Utworzyłeś swój plik testowy w systemie Windows, więc niezależnie od narzędzia, którego użyłeś do zrobienia tego, dołączyłeś control-M na końcu każdej linii, więc ostatnie pole w każdej linii toClNonZ<control-M> , a nie ClNonZdlatego częściowe porównanie RE, takie jak wykonane za pomocą grep lub "~ "w awk znajduje to, ale porównanie równości nie.
Ed Morton,
2
Tak, ma sens. Wypróbowałem test $ dos2unix, a następnie użyłem „==” do zastąpienia „~” i działa. Dziękuję za wyjaśnienie!
user1687130
-3

proszę spróbuj tego

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

lub

echo cat filename | grep ClNonZ | awk '{print $3}';
Mustafa
źródło
Niestety ta odpowiedź w rzeczywistości nie używa składni Awk, o którą konkretnie prosił użytkownik!
Asfand Qazi