I want to print the second last column or field in awk. The number of fields is variable. I know that I should be able to use $NF
but not sure how it can be use
You weren't far from the result! This does it:
awk '{NF--; print $NF}' file
This decrements the number of fields in one, so that $NF
contains the former penultimate.
Let's generate some numbers and print them on groups of 5:
$ seq 12 | xargs -n5
1 2 3 4 5
6 7 8 9 10
11 12
Let's print the penultimate on each line:
$ seq 12 | xargs -n5 | awk '{NF--; print $NF}'
4
9
11
Perl solution similar to Chris Kannon's awk solution:
perl -lane 'print $F[$#F-1]' file
These command-line options are used:
n
loop around every line of the input file, do not automatically print every line
l
removes newlines before processing, and adds them back in afterwards
a
autosplit mode – split input lines into the @F
array. Defaults to splitting on whitespace
e
execute the perl code
The @F
autosplit array starts at index [0] while awk fields start with $1.
$#F
is the number of elements in @F
First decrements the value and then print it -
awk ' { print $(--NF)}' file
OR
rev file|cut -d ' ' -f2|rev
Small addition to Chris Kannon' accepted answer: only print if there actually is a second last column.
(
echo | awk 'NF && NF-1 { print ( $(NF-1) ) }'
echo 1 | awk 'NF && NF-1 { print ( $(NF-1) ) }'
echo 1 2 | awk 'NF && NF-1 { print ( $(NF-1) ) }'
echo 1 2 3 | awk 'NF && NF-1 { print ( $(NF-1) ) }'
)
It's simplest:
awk '{print $--NF}'
The reason the original $NF--
didn't work is because the expression is evaluated before the decrement, whereas my prefix decrement is performed before evaluation.
If you have many columns and want to print all but not the three cloumns in the last, then this might help
awk '{ $NF="";$(NF-1)="";$(NF-2)="" ; print $0 }'