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. –  Jan 09 '15 at 19:20
  • 3
    Piped processes are run in a subshell. – muru Jan 09 '15 at 19:30

2 Answers2

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.

jordanm
  • 42,678
mdpc
  • 6,834
1

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.

mikeserv
  • 58,310
  • Hey mikeserv, I took some ideas from this answer and used them to write https://unix.stackexchange.com/a/541908/135943, but I feel there are nuances I may have missed—I couldn't get my answer to work by deleting the named pipe before use. If you'd like to take a look I'd appreciate it. :) – Wildcard Sep 15 '19 at 20:12