1

How to print the word before the last word in line (with ksh or awk or sed or perl one liner)

Example 1:

  echo one two three

will print "two"

Example 2:

 echo 1 2 3 4 5 6

will print "5"

  • Pure ksh: n=1 a=( 1 2 3 4 5 6 ) && echo ${a[${#a}-n-2]}, but the awk solution has my preference. – Henk Langeveld Mar 13 '14 at 9:43
  • 1
    @HenkLangeveld, or "${a[-2]}" in zsh or recent versions of ksh93 or bash or "${a[@]: -2:1}" in older versions of ksh93 or bash (or newer zsh). Note that none of them work for sparse arrays (zsh arrays are never sparse). – Stéphane Chazelas Mar 14 '14 at 11:14
7

With awk:

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

NF is the number of fields -- all that happens here is that one is subtracted from the total field length to get the penultimate field.

With perl:

perl -lane 'print $F[-2]'

An array containing the fields is created as @F (that's what -a does), and we get the value of the second last field (with index -2).

Using sed is slightly less palatable, since it doesn't have any concept of fields. I'd recommend using one of the above, instead.

  • Do you confuse when saying arrayref? I think it is just array. – cuonglm Mar 12 '14 at 16:35
3

I put the below in a subshell so you don't change your current environment too drastically - they're all native shell builtins.

(set -f; unset IFS ; set -- ${line}
 shift "$((${#}${2+-2}))" && printf ${2+%s}'\n' "$1")

I edited this to disallow globbing - I added set -f according to advice offered in the comments below.

  • 1
    This will fail if your expansion contains globs, among other things. – Chris Down Mar 12 '14 at 16:17
  • What does that mean? Expansion of what, the last word? Oh, you mean pathname expansion. That's a good point. I'll fix it. Thanks, man. – mikeserv Mar 12 '14 at 16:21
  • 1
    Your -f will apply only once that set command is executed, so not for the expansion of $line above. You need set -f; set -- $line. – Stéphane Chazelas Mar 14 '14 at 10:59
  • You unset the IFS - some shells will handle that differently than others, right? I remember reading something recently on a mailing list about unspecified behavior if IFS is unset... Or maybe it was \0... Anyway, the check for enough positionals is appreciated. – mikeserv Mar 14 '14 at 11:32
1

rev | cut -d ' ' -f 2 | rev

or

rev | awk '{print $2}' | rev

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy