[ILUG] Logging and displaying output of shell commands
Brian Foster
blf at utvinternet.ie
Tue Oct 7 18:29:29 IST 2008
| Date: Tue, 7 Oct 2008 12:03:38 +0100
| From: Darragh Bailey <felix at compsoc.nuigalway.ie>
|[ ... ]
| make macro
| log = $(if $(filter 2,$(V)),2>&1 | tee -a $1,>> $1 2>&1)
|
| Problem occurs that if V=2, tee is used which results in the wrong exit
| code being received by the make rule.
|
| i.e.
| rule:
|
| somerule:
| @some_command $(call log,mylog.log)
|
| With V=1, this becomes:
| somerule:
| @some_command >> mylog.log 2>&1
|
| With V=2, this becomes:
| somerule:
| @some_command 2>&1 | tee -a mylog.log
|
| Problem is that when there is an error executing some_command and V=2,
| then make only receives the exit code of tee, which barring some problem
| in tee itself is always going to be 0.
|
| Any suggestions on how to get the output to go to the log file in all
| three cases while still resulting in the correct exit code being given
| to make?
well, I'd tell the user to run:
make V=1 RULE 2>&1 | tee -a FILE
but I do understand people don't do that when they should.
(there's numerous variations on the idea, such as using
script(1) or other session-logging commands.)
so, continuing with yer basic approach, and assuming the
underlying shell is a fairly modern version of GNU bash(1),
then try changing the rule's expansion from:
some_command 2>&1 | tee -a mylog.log
to:
set -o pipefail; some_command 2>&1 | tee -a mylog.log
from the bash(1) 3.2 man page:
If [`pipefail' is] set, the return value of a
pipeline is the value of the last (rightmost)
command to exit with a non-zero status, or zero
if all commands in the pipeline exit successfully.
This option is disabled by default.
an older trick, albeit still GNU `bash'-only, is
(I'm omitting all the spurious backslashes (\),
semicolons (;), &tc used in make(1)'s baroque syntax):
some_command 2>&1 | tee -a mylog.log
for sts in ${PIPESTATUS[*]}; do
[ $sts -eq 0 ] || exit $sts
done
WARNING: there must NOT be any commands between the pipe
and the `for'-loop. every command changes `PIPESTATUS'.
the oldest(?) trick of all, which works in most(? all?)
Bourne-ish shells (excepting the obvious trick of using
a temporary file instead of piping to tee(1)) is:
( some_command; echo $? >ERR ) 2>&1 | tee -a mylog.log
read sts <ERR && [ "$sts" -eq 0 ] || exit 1
(there's numerous variations on using a temporary file
to communicate the exit status, such as using a FIFO.)
hope this helps. (all of the examples above were just
typed in without testing. apologies for any mistakes.)
cheers!
-blf-
--
“How many surrealists does it take to | Brian Foster
change a lightbulb? Three. One calms | somewhere in south of France
the warthog, and two fill the bathtub | Stop E$$o (ExxonMobil)!
with brightly-coloured machine tools.” | http://www.stopesso.com
More information about the ILUG
mailing list