223

I want to print the second-to-last column or field in awk. The number of fields is the NF variable. I know that I should be able to use $NF, but I'm not sure how it can be used.

And this does not seem to work:

awk ' { print ( $NF-- ) } ' 
2
  • 12
    NF is the last field index, $NF is the value of the last field Commented Jan 19, 2010 at 21:00
  • that makes sense now. thats why the dollar outside the parenthesis works I suppose Commented Feb 11, 2010 at 17:09

10 Answers 10

380
awk '{print $(NF-1)}' 

Should work

Sign up to request clarification or add additional context in comments.

11 Comments

This does not work for me. I get "title:5: command not found: NF-1" in awk 3.1.8 under Ubuntu.
I would avoid the pre/post decrement to make sure you don't change the value of $NF
This breaks if you try to get the third last field like awk -F '.' '{print $(NF-2)}'
@Gurgeh: This happens because $(..) invokes a command in a subshell depending on which shell you're using. You can work around this by using $ (NF-1) instead of $(NF-1).
@wting : ur interpretation is entirely off the mark - there's nothing related to the shell here - $(…) is just a way to grouping operations inside awk that yields an outcome that could be evaluated to a certain field number. you can do $( atan2(0, -1) ) if you like - it'll simply become $(3.14159…) which is then auto truncated to $3. gawk and nawk are even willing to accept +/- nan as a valid NF
|
25

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) ) }' ) 

Comments

24

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.

2 Comments

As a mnemonic, this behavior is the same as C/Java etc. int x = ++i int x = i++, prefix means increment first; postfix means increment later (assignment first).
Adding to this excellent answer, you just need to check whether there's more than one field, otherwise you wind up printing $0 (aka: the whole string). So even modified, it's still the simplest answer: awk 'NF>1{print $--NF}'.
11
awk ' { print ( $(NF-1) ) }' file 

Comments

9

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.

Test

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 

Comments

6

First decrements the value and then print it -

awk ' { print $(--NF)}' file 

OR

rev file|cut -d ' ' -f2|rev 

Comments

4

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

1 Comment

or use the negative indexing already provided by perl... $F[-2]
4

Did you tried to start from right to left by using the rev command ? In this case you just need to print the 2nd column:

seq 12 | xargs -n5 | rev | awk '{ print $2}' | rev 4 9 11 

Comments

1

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 }'

1 Comment

if you wanna get anything but last 3, this will do : mawk '3 < NF && NF -= 3' Sat Jul 9 12:30:20 EDT 2022 Sat Jul 9
0
date Sat Jul 9 11:57:36 EDT 2022 date | gawk '$_=$--NF' | mawk '$!--NF=$NF' 
EDT 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.