How to get 2nd last column of the line- UNIX?

I want to retrieve Status from below example. Columns numbers will be dynamic but Status will always be 2nd last-

JobName StartTime EndTime Status ExitCode
autorep -j $jobName | grep '^FR' | awk -F' ' '{print $2}' 

The above code gives me the 2nd column from start of the line.

Hello Tanu,

Please use code tags as per forum rules for your commands/codes/Inputs which you are using into your posts. Following may help you in same.

autorep -j $jobName | grep '^FR' | awk  '{print $(NF-1)}'

Where $NF defines last field of each record/line. So $(NF-1) defines the second last field of each line. Similarly you could get 3rd field from last by $(NF-2) and so on.

Thanks,
R. Singh

1 Like

Then

autorep -j $jobName | grep '^FR' | awk -F' ' '{print $NF}' 

will give you the last field and:

autorep -j $jobName | grep '^FR' | awk -F' ' '{print $(NF - 1)}' 

will give you the next to the last field.

1 Like

If they are space separated and you can be certain that Status will always be the penultimate one, you could use variable substitution:-

status_line=$(autorep -j $jobname | grep -E "^FR" )                # Catch the whole messages
status="${status_line#${status_line% * *}"                         # Chop off everything except the last two fields
status="${status% *}"                                              # Chop off the last field

There is also the awk way to do this, but it could be expensive if you call this in a loop. The above is all within the shell process.

How will you be running this?

I hope that this helps,
Robin

Bah, Don has beaten me to the punch! ;\)
1 Like

Thanks R.Singh. I'll make sure I'm using code/tags for my next posts.
The solution provided by you worked and I have learned something (NF). Cheers :slight_smile:

---------- Post updated at 04:48 AM ---------- Previous update was at 04:46 AM ----------

@rbatte1 -Thanks for explaining. Really helpful

Hi Robin,
It looks like I beat you by about 3 minutes; but Ravinder also beat me by a few seconds.

What you suggested will be faster than what Ravinder and I suggested as long as there is only one line of output selected by the grep . But, I think you had a slight typo... The line:

status="${status_line#${status_line% * *}"                 # Chop off everything except the last two fields

has mismatched braces. I think you meant:

status="${status_line#${status_line% * *}}"                # Chop off everything except the last two fields

If more than one line is selected by the grep the awk solutions will yield the next to the last field on each selected line while your suggestion will just yield the next to the last field on the last line. I have no idea whether or not the command:

autorep -j "$jobname" | grep -E "^FR"

could produce more than one line of output.

Yes, indeed it was left off in error.

I suppose to deal with multi-record output, one could:-

while read status_line
   status="${status_line#${status_line% * *}}"                # Chop off everything except the last two fields
   status="${status% *}"                                      # Chop off the last field
   .... do whatever here ....
done< <(autorep -j $jobname | grep -E "^FR" )

Would that be any better?
I could make the substitution a single line, but it would get awfully complicated and a not great to support.

Robin

As long as your shell supports < <(command_list) command substitution redirection (which recent versions of bash and ksh do; but will be a syntax error in many other shells), that should be fine.

And, of course, we could also get rid of the grep and build that into the shell script as well. Here is a sample doing that just using standard POSIX shell features:

#!/bin/ksh
jobName="whatever"

autorep -j "$jobName" |
while read -r line
do	case "$line" in
	(FR*)	status=${line% *}	# Drop last field
		status=${status##* }	# Drop all but last remaining field
		printf 'Extracted "%s" from "%s"\n' "$status" "$line"
		;;
	(*)	printf 'Skip "%s"\n' "$line"
		continue
		;;
	esac
	printf '\n*** Do whatever you want with "%s"\n\n' "$status"
done

I have no idea what output autorep produces, but with an autorep that produces the output:

JobName StartTime EndTime Status ExitCode
FR1 st1 et1 Status_1 eco
FR2 st2 et2 Status_2 ec2
3FR st3 et3 Status_3 eco
FR4 st4 et4 Status_4 ec4

the above script produces the output:

Skip "JobName StartTime EndTime Status ExitCode"
Extracted "Status_1" from "FR1 st1 et1 Status_1 ec1"

*** Do whatever you want with "Status_1"

Extracted "Status_2" from "FR2 st2 et2 Status_2 ec2"

*** Do whatever you want with "Status_2"

Skip "3FR st3 et3 Status_3 ec3"
Extracted "Status_4" from "FR4 st4 et4 Status_4 ec4"

*** Do whatever you want with "Status_4"

But, of course, unless Tanu gives us more details about the output autorep -j "$jobName" produces, we have no idea how complex a working script needs to be.