I'm familiar with using tee, and I know that I can simply log output with

script.sh | tee file.log

However, I want a seamless interface for the user. Is there a way to, within script.sh, run tee as if it was being done as above? Within this script there are hundreds of echoes and lots of other scripts being run, it would be difficult to individually append each to file.

1 Answer 1


Solution 1: exec

You may place an exec command at the beginning of the script:

$ cat script1
exec > >(tee file.log)
echo one
echo two

Here is an example of running script1:

$ bash script1
$ one


Observe that the shell prompt returned before the output from the script was complete. This is because the output went to a subprocess and, due to vagaries of multitasking, it completes on its own schedule. For this reason, I prefer the second solution shown below:

Solution 2: grouping

You can put the entire script in a shell group, {...}, and then redirect output from the group:

$ cat script2
echo one
echo two
} | tee file.log

This can be done for arbitrarily complex scripts. Just put { at the beginning and } | tee file.log at the end.

A sample run looks like:

$ bash script2

Notice that the output neatly completes before the prompt returns.

  • The tee approach works well, and I'm now using it. Is there a way (using date) to timestamp each line as well with this approach? Jul 25, 2016 at 13:36
  • @BrydonGibson Try: ... | while read -r line; do echo "$(date +%Y-%m-%d-%H:%M:%S)" "$line"; done | tee file.log
    – John1024
    Jul 25, 2016 at 16:30
  • That will timestamp stdout as well, won't it? At the moment I'm working on tee-ing to a named pipe and then using a similar method to yours. Jul 25, 2016 at 17:04
  • Update to this: Create a named pipe, Spawn a while loop (like yours) in the background, but instead read from a named pipe, THEN run the script and tee the file. The background loop waits for output to the pipe and the script runs seamlessly. Jul 25, 2016 at 18:11
  • 1
    Note, this doesn't write STDERR to the log, only to the console. To merge them together, add 2>&1, like so: exec > >(tee -a $log_path) 2>&1
    – HeroCC
    Jun 16, 2020 at 16:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .