Jak wydrukować ostatnie dwie kolumny za pomocą awk

106

Chcę tylko wydrukować dwie ostatnie kolumny.

Vehomzzz
źródło
6
Nie do końca jestem pewien, dlaczego ma to 87 głosów za, z pewnością można to poprawić przynajmniej za pomocą przykładu.
Arj
Prawdopodobnie dlatego, że pytanie jest z natury niezwykle proste i łatwe do zrozumienia bez przykładu, co jest rzadkością, ale w tym przypadku wydaje się działać. Myślę, że tutaj problemem nie jest brak informacji, ale raczej brak niezależnych badań.
DryLabRebel
To pytanie jest również duplikatem tego pytania.
DryLabRebel
Czy to odpowiada na twoje pytanie? Wydrukuj przedostatnią kolumnę / pole w awk
DryLabRebel

Odpowiedzi:

194

Możesz skorzystać ze zmiennej, NFktóra jest ustawiona na całkowitą liczbę pól w rekordzie wejściowym:

awk '{print $(NF-1),"\t",$NF}' file

przy założeniu, że masz co najmniej 2 pola.

codaddict
źródło
1
Potrzebujesz przecinka - ponieważ jesteśmy dziś wybredni: spacja łączy pola, przecinek oddziela pola w instrukcji print. To połączy oba pola
Jim Mcnamara
18
Teraz drukujesz "pole-OFS-tab-OFS-pole". Powinien być awk '{print $(NF-1) "\t" $NF}' filelub awk '{print $(NF-1), $NF}' filelub awk 'BEGIN{OFS="\t"} {print $(NF-1), $NF}' file.
Wstrzymano do odwołania.
Aby dodać do poprzedniego komentarza, problem z użyciem '{print $x,"\t",$y}'polega na tym, że awk interpretuje każdą zmienną oddzieloną przecinkami jako swoje własne pole, więc wynikiem będzie faktycznie field1<space><tab><space>field2(ponieważ domyślnie użyje separatora spacji), w przeciwieństwie do field1<tab>field2tego, co prawdopodobnie spodziewasz się. używanie separatora pól wyjściowych (OFS) jest prawie zawsze tym, czego potrzebujesz.
DryLabRebel
13
awk '{print $NF-1, $NF}'  inputfile

Uwaga: działa to tylko wtedy, gdy istnieją co najmniej dwie kolumny. W przypadku rekordów z jedną kolumną otrzymasz fałszywy"-1 column1"

jim mcnamara
źródło
3
Spróbuj i zobacz. Działa w Solaris 9 awk i nawk. Alternatywą jest $ (NF-1)
jim mcnamara
1
@coaddict - Domyślam się, że nie pracowałeś z różnymi implementacjami awk. Stare zachowania awks zostały (być może błędnie) przeniesione do przodu. Nie mam gawk do testowania - do czego prawdopodobnie się odnosisz. Więc nie wiem na pewno, dlaczego twój komentarz został odrzucony. Linux awk po wyjęciu z pudełka to zwykle gawk. Przetestuję i wrócę. W międzyczasie spróbuj Soalris, HPUX, DGX lub czegokolwiek, aby zobaczyć, co mam na myśli przez stary awk.
jim mcnamara
6
Prawdopodobnie zostałeś oszukany i pomyślałeś, że to działa, ponieważ próbowałeś echo 1 2 3 | awk .... $NF-1jest ($NF) - 1w każdej awkrealizacji.
Stephane Chazelas
Kod źródłowy „One True Awk” zawiera ponad 40 konfliktów yaccgramatycznych, co jest ironiczne, biorąc pod uwagę znaczenie litery A w awk. Różne wersje awk inaczej analizują rzeczy? Wielka niespodzianka!
Kaz,
1
@THESorcerer, spróbuj z echo '5 4 3 2 1' | awk '{print $NF-1,$NF; print $(NF-1), $NF}'- lub jakimkolwiek innym wejściem, w którym drugie ostatnie pole jest nie mniejsze niż ostatnie pole.
glenn jackman
6

@jim McNamara: spróbuj użyć nawiasów dla dokoła NF, czyli $(NF-1)i $(NF)zamiast $NF-1a $NF(działa na Mac OS X 10.6.8 dla FreeBSD awki gawk).

echo '
1 2
2 3
one
one two three
' | gawk '{if (NF >= 2) print $(NF-1), $(NF);}'

# output:
# 1 2
# 2 3
# two three
guzo
źródło
Rozważaliśmy już () wcześniej. Myślałem, że dyskutujemy, skąd wzięło się oryginalne zachowanie starego awk.
jim mcnamara
+1 za odpowiedź z wyraźnym $(NF-1)- co najmniej jest bardziej przenośne niż $NF-1; jest zdecydowanie mniej niejednoznaczny. $(NF)jest przesadą - po prostu wystarczy $NF. Warto też chronić się przed wierszami z mniej niż 2 kolumnami, ponieważ w przypadku wierszy jednokolumnowych wartość pierwszej kolumny zostanie wyświetlona dwukrotnie , a przy wierszach z zerową kolumną - tj. Pustych - polecenie awk całkowicie się nie powiedzie z powodu próby dostęp do pola o indeksie -1.
mklement0
1

użycie gawk wykazuje problem:

 gawk '{ print $NF-1, $NF}' filename
1 2
2 3
-1 one
-1 three
# cat filename
1 2
2 3
one
one two three

Właśnie umieściłem gawk na Solarisie 10 M4000: Więc, gawk jest cuplritem w kwestii $ NF-1 kontra $ (NF-1). Następne pytanie, co mówi POSIX? za:

http://www.opengroup.org/onlinepubs/009695399/utilities/awk.html

Nie ma żadnego kierunku w jedną lub drugą stronę. Niedobrze. gawk implikuje odejmowanie, inne awks wymagają odejmowania lub numeru pola. hmm.

jim mcnamara
źródło
1
Pierwsze 2 wiersze przykładowego pliku wejściowego nie są pomocne, ponieważ dają takie same wyniki w obu przypadkach . Czy możesz potwierdzić, że Solaris awk rzeczywiście NIE zachowuje się w tym przypadku jak gawk?
mklement0
Jeśli chodzi o twoje łącze do specyfikacji awk: niepotwierdzonym argumentem za użyciem $(NF-1)jest to, że oba przykłady obliczania indeksu pola w specyfikacji używają tej postaci: $(NF-1)i $(NF+2). Następnie jest sekcja „Wyrażenia w awk”, w której wymieniono $exprjako mające [znacznie] wyższy priorytet niż expr - expr. Ponieważ NFsamo w sobie jest wyrażeniem, $NF-1należy obliczyć ($NF)-1. Nawet JEŚLI w końcu istnieją implementacje awk, które oceniają $NF-1jako $(NF-1), wyciągnięta tutaj lekcja jest taka, że ​​używanie $(NF-1)jest bezpiecznym i przenośnym wyborem.
mklement0
0

spróbuj z tym

$ cat /tmp/topfs.txt
/dev/sda2      xfs        32G   10G   22G  32% /

awk print last column
$ cat /tmp/topfs.txt | awk '{print $NF}'

awk print before last column
$ cat /tmp/topfs.txt | awk '{print $(NF-1)}'
32%

awk - print last two columns
$ cat /tmp/topfs.txt | awk '{print $(NF-1), $NF}'
32% /
namasivayam.cse
źródło
0

Spróbuj tego, aby wziąć pod uwagę wszystkie możliwe scenariusze:

awk '{print $(NF-1)"\t"$NF}'  file

lub

awk 'BEGIN{OFS="\t"}' file

lub

awk '{print $(NF-1), $NF} {print $(NF-1), $NF}' file
Marios
źródło