VeryStrange
VeryStrange

Reputation: 61

Why redirection with tee doesn't work as expected?

What I want to obtain is logging all the output of a script to a file, all in the script itself, saving all I see on the screen in the log file. If I don't redirect to file the script works as intended, continuing to loop forever till I hit CTRL+C; when this happens it prints a couple of messages on screen and quits. If I try to redirect to a file, using tee, not only it doesn't print the messages but also the log is incomplete, there's only the loop lines, nothing afte that. Here's the script (cut down version):

#!/bin/sh
EXIT=0
COUNT=0
{
while [ $EXIT -eq 0 ]
do
  COUNT=$((COUNT+1)) && echo "Eternal loop $COUNT" && sleep 1
  trap 'EXIT=1; echo "Loop interrupted by user, exiting."' 15 2 8 20
done
echo "Out of loop, eternity ends"
} | tee log.log 2>&1

I read around and couldn't understand if the issue I have is caused by piping to tee, by stderr and stdout, or by how I useda trap. I'm a noob at shell scripting and this is frustrating, any help will be appreciated. Thanks.

Edit 1: After reading chepner's answer I modified the script like this:

#!/bin/sh
EXIT=0
COUNT=0
rm log.log
while [ $EXIT -eq 0 ]
do
COUNT=$((COUNT+1)) && echo "Eternal loop $COUNT" | tee -a log.log && sleep 1
trap 'EXIT=1; echo "Loop interrupted by user, exiting." | tee -a log.log' 15 2 8 20
done
echo "Out of loop, eternity ends" | tee -a log.log

and it works, it logs the output to a logfile, and I still see the output on screen, exactly how I wanted. Will have to try it on the other script, but I suppose it'll be OK. Now a question remains: if I have lots of commands instead of just 3, would this solution be "clean" enough? I mean, what happens to all those tee I call forth? Is there a better way to do this, like more polished?

Upvotes: 4

Views: 7538

Answers (3)

chepner
chepner

Reputation: 532303

With the pipeline, the foreground job consists of two processes, one for each side of the pipeline. Hitting Control-C sends SIGINT to all processes, so that there is no chance for the post-loop echo to run, or for tee to output the final output of the LHS process. Without the pipe to tee, the while loop is running entirely inside the current shell instance, so the the shell itself receives the SIGINT and (I believe) only interrupts whatever shell command is currently running in the loop. The trap fires, and then the loop exits naturally as a result of the condition check on EXIT.

Upvotes: 3

genisage
genisage

Reputation: 1169

Not exactly what you're asking, but when you want to log everything you see during a process, the script command is easier than dealing with redirection.

if you want to use tee anyway, move the redirection in front of the pipe

somecommand 2>&1 | tee outfile

Upvotes: 6

plesiv
plesiv

Reputation: 7028

Maybe you want to redirect stderr to stdout and then pipe to tee command:

...
} 2>&1 | tee log.log

Upvotes: 1

Related Questions