Larrrrrrrrrry Larrrrrrrrrry - 11 months ago 43
Linux Question

Bash output to screen and logfile differently

I have been trying to get a bash script to output different things on the terminal and logfile but am unsure of what command to use.

For example,

freespace=$(df -h / | grep -E "/" | awk '{print $4}')
logdate=$(date +"%Y%m%d")

exec > >(tee -i $logfile)

echo -e $bold"Quick system report for "$greentext"$HOSTNAME"$normal
printf "\tSystem type:\t%s\n" $MACHTYPE
printf "\tBash Version:\t%s\n" $BASH_VERSION
printf "\tFree Space:\t%s\n" $freespace
printf "\tFiles in dir:\t%s\n" $(ls | wc -l)
printf "\tGenerated on:\t%s\n" $(date +"%m/%d/%y") # US date format
echo -e $greentext"A summary of this info has been saved to $logfile"$normal

I want to omit the last output (echo "A summary...") in the logfile while displaying it in the terminal. Is there a command to do so? It would be great if a general solution can be provided instead of a specific one because I want to apply this to other scripts.

EDIT 1 (after applying >&6):

Files in dir: 7
A summary of this info has been saved to 20160915_report.log
Generated on: 09/15/16

cxw cxw
Answer Source

One option:

exec 6>&1    # save the existing stdout
exec > >(tee -i $logfile)   # like you had it
#... all your outputs
echo -e $greentext"A summary of this info has been saved to $logfile"$normal >&6   
    # writes to the original stdout, saved in file descriptor 6  ------------^^^

The >&6 sends echo's output to the saved file descriptor 6 (the terminal, if you're running this from an interactive shell) rather than to the output path set up by tee (which is on file descriptor 1). Tested on bash 4.3.46.

References: "Using exec" and "I/O Redirection"

Edit As OP found, the >&6 message is not guaranteed to appear after the lines printed by tee off stdout. One option is to use script, e.g., as in the answers to this question, instead of tee, and then print the final message outside of the script. Per the docs, the stdbuf answers to that question won't work with tee.

Try a dirty hack:

#... all your outputs
echo >&6  # <-- New line
echo -e $greentext ... >&6

Or, equally hackish, (Note that, per OP, this worked)

#... all your outputs
sleep 0.25s   # or whatever time you want  <-- New line
echo -e ... >&6