jimx0r: (Default)
jimx0r ([personal profile] jimx0r) wrote2012-07-31 08:52 am

How in the heck do I get reasonable command logging?

So, what I'd really really like is to be able to run a command and dump the output of the command to a logfile. I *need* to be able to check on the return status of the command (so a simple cmd.exe | tee -a $LOGFILE will not work as the return value is that of the tee command and not the cmd.exe!) so that I can do sensible things inside the rest of my shell script.

So far, I've come up with this bit of code that runs the command, saves the output of the command to the variable CMDOUT, saves the return value of the command to RET, barfs the output of the command into the logfile (and to STDOUT) and then returns the same return value as the command.

# write stuff to a log file
# Call like this: log_it "command1 | command2 ; command3 & command4" or whatever set of shell commands you'd like
function log_it () {
  cmds=$@
  RET=42 
  TMPFILE=$(mktemp)
  CMDOUT=$(/bin/bash -c "$cmds" 2>&1)
  RET=$?
  echo "$CMDOUT" | tee -a $LOGFILE
  return $RET
}
What I *really really hate* about the above code is that I cannot see the output of the command until the command has completed.  I'd really like the behavior to be more like the naive implementation using tee that I alluded to above in that I see the output as it happens... except, of course, that I *need* that return code!
vatine: Generated with some CL code and a hand-designed blackletter font (Default)

[personal profile] vatine 2012-07-31 04:12 pm (UTC)(link)
Do you want/need STDERR and STDOUT separated or in the same file?

If you're only after the latter, I think the following might do the trick (may be bash-only, may be POSICX-compliant, use with care, no warranties, etc, etc, so on and so forth):
exec 3>&1 # Save current stdout on fd 3
exec > /tmp/log 2>&1 # redirect stdout and stderr to the log file
tail -f /tmp/log >&3 &  # Start a tail
"$@"  # execute the passed-in command line
RV=$? # save exit status
kill %tail # kill the output
wait # wait for it to finish
exit $RV # and pass back the saved exit status


Simply pass in the script you want to log. If you want stdout and stderr archived separately, it gets a bit trickier. Also, you may want to use a sensible way of picking the log file.
vatine: Generated with some CL code and a hand-designed blackletter font (Default)

Re: Nice Hack!

[personal profile] vatine 2012-07-31 06:08 pm (UTC)(link)
It's relatively simple in C...