Suppose you have a bash script and you want to print and also save the output (stderr, and stdout) to a log file. Based on this answer: https://stackoverflow.com/a/49514467/835098 by @cdarke, this is how you can do it.
#!/bin/bash
exec > >(tee my.log) 2>&1
echo "Hello"
But what if you have a script where different sections need to go to different log files? Let's say you want to separate the typical configure, make, make test output each into their individual log file? A naive approach could look like this (for the sake of simplicity configure and alike became echos here):
#!/bin/bash
# clear logs
rm -f configure.log make.log make_test.log
exec > >(tee configure.log) 2>&1
echo "configure"
exec > >(tee make.log) 2>&1
echo "make"
exec > >(tee make_test.log) 2>&1
echo "make test"
But when you execute this script, you'll notice that only the last output contains what it's supposed to contain:
$ tail *.log
==> configure.log <==
configure
make
make test
==> make.log <==
make
make test
==> make_test.log <==
make test
Also notice that each log file begins with the correct output. I thought about sticking with one log file and truncating it after copying an intermediate piece of it to the final destination. This script works but I wonder if it is any good:
#!/bin/bash
# clear logs
rm -f configure.log make.log make_test.log tmp.log
exec > >(tee tmp.log) 2>&1
echo "configure"
cp tmp.log configure.log && truncate -s 0 tmp.log
echo "make"
cp tmp.log make.log && truncate -s 0 tmp.log
echo "make test"
cp tmp.log make_test.log && truncate -s 0 tmp.log
Here are the resulting log files:
$ tail *.log
==> configure.log <==
configure
==> make.log <==
make
==> make_test.log <==
make test
==> tmp.log <==
For example one downside of this approach is that a final log file will be available if the command succeeded. Actually, this is pretty bad and a good reason to find another solution.