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?
bash
, you can usePIPESTATUS
instead of$?
:exit 13 | tail -n1; echo ${PIPESTATUS[0]}
– Mar 31 '19 at 17:14grade=$(./a.out | tail -1; test ${PIPESTATUS[0]} = 0 || echo 5)
– Mar 31 '19 at 18:57grade=$({ ./a.out || echo 5; } | tail -n1)
– Mar 31 '19 at 19:02