3

I want to send STDOUT for a script block to a file which name is defined by a variable within the block. However, when I use tee, it seems the variable outside the block doesn't exist anymore. Without tee, the variable still exists.

Script:

#!/bin/bash
{
    log="mylog.txt"
    echo log: $log
} |tee $log

echo log: $log

Result:

log: mylog.txt
log:

and no mylog.txt file produced by tee.

  • Try echo log: $$ '->' $log instead of just echo log: $log. Both echo instructions are run in a different shell instance. – user86969 Jan 9 '15 at 19:20
  • 2
    Piped processes are run in a subshell. – muru Jan 9 '15 at 19:30
3
 #!/bin/bash
 log="mylog.txt"
 {
     echo log: $log
 } |tee $log

The pipeline causes the command list to be executed in a sub-shell. As the variable was in a different sub-shell, this could not be communicated up. Thus you have to move the variable up into a common context to be properly used.

  • is there a way to do it without a pipe? I need to define my variable within the block. Any other way than tee to log both STDOUT and STDERR for the entire script execution would make my day. – Sébastien Clément Jan 9 '15 at 21:51
  • 1
    @SébastienClément What is your actual problem? – muru Jan 9 '15 at 22:37
0

A named pipe could work for you. With only a little bit more work you can get one robustly and without having to setup traps or similar to handle file-system cleanup afterward - you just do the cleanup beforehand.

pipe=/tmp/$$pipe log=mylog.txt
mkfifo "$pipe"; exec 3<>"$pipe"
{ rm "$pipe"; tee "$log"; } <&3 >/dev/tty &
pipe=$!; exec >&3 3>&-

There. From this moment on all of the script's output is being written to a (used-to-be) named pipe that is being read by a back-grounded tee process. The named pipe's special file has already been removed from the file-system and so it need not be cleaned-up later and the only references to it that remain are the file-descriptors assigned to your script's stdout and tee's stdin.

That said, it could be wise to setup at least one trap:

trap "kill PIPE $pipe" 0

...just to ensure that tee doesn't hang out in the background after your script exits.

If you run into buffering issues - which shouldn't be a problem, I think, since tee has an open line on /dev/tty - you might try your luck calling tee via stdbuf. stdbuf's man page specifically hedges its bets where is tee concerned though - it notes tee as an application that is likely to readjust its own buffers after invocation - but is more positive about the interaction than it is for dd anyway.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.