Bash – How to get either the last line of output or the exit code

bashscripting

I am writing an automated homework grader in bash. The grader compiles a program and runs it. If the program fails to compile or fails to run (e.g. due to a segmentation fault) the grade should be a fixed small number, e.g. 5. Otherwise, the grade is the last line output by the program.

To get the last line, I can do:

grade=$( ./a.out | tail -1 )

But this always gives an exit code of 0, even if a.out fails to run (e.g. not found), so I cannot tell whether the program failed to exist.

Another option is to use a temporary file:

./a.out > temp
if [ $? -ne 0 ]
then
  grade=0
else
  grade=$( tail -1 temp )
fi

However, this might be problematic if there are many different processes doing the same simultaneously. Even with one process, it is wasteful to keep all output in a file (the output might be large) when I only need the last line.

Is there a solution that does not use a temporary file?

Best Answer

grade=$( { ./a.out 2>/dev/null || echo 0; } | tail -n 1 )

This would try to execute ./a.out and then add a line with a single 0 to its output if that program exited with a non-zero exit status or failed to execute at all. The 0 would be caught by tail -n 1 and placed in $grade.

If ./a.out executed correctly and terminated with a zero exit status, the echo would not be triggered.

Remove the redirection of standard error to /dev/null if you are interested in seeing diagnostic messages related to running ./a.out.

Change the 0 to "$?" to get the exit code instead. To be able to differentiate a number from an error, you may want to use NaN instead, or some error string.

Related Question