My intent was to have all the output of my bash script displayed on the console and logged to a file.
Here is my script that works as expected.
#!/bin/bash
LOG_FILE="test_log.log"
touch $LOG_FILE
# output to console and to logfile
exec > >(tee $LOG_FILE) 2>&1
echo "Starting command ls"
ls -al
echo "End of script"
However I do not understand why it works that way.
I expected to have exec >>(tee $LOG_FILE) 2>&1
work but it fails although exec >>$LOG_FILE 2>&1
indeed works.
I could not find the reason for the construction exec > >(command )
in the bash manual nor in advanced bash scripting. Can you explain the logic behind it ?
On Unix-like operating systems, exec is a builtin command of the Bash shell. It allows you to execute a command that completely replaces the current process. The current shell process is destroyed, and entirely replaced by the command you specify.
The tee command reads from the standard input and writes to both standard output and one or more files at the same time. tee is mostly used in combination with other commands through piping.
The tee command, used with a pipe, reads standard input, then writes the output of a program to standard output and simultaneously copies it into the specified file or files. Use the tee command to view your output immediately and at the same time, store it for future use.
The Linux exec command executes a Shell command without creating a new process. Instead, it replaces the currently open Shell operation. Depending on the command usage, exec has different behaviors and use cases.
The >(tee $LOG_FILE)
is an example of Process substitution, you might wish to search for that. Advanced Shell Scriptng and Bash manual
Using the syntax, <(program)
for capturing output and >(program)
for feeding input, we can pass data just one record at a time. It is more powerful than command substitution (backticks, or $( )
) because it substitutes for a filename, not text. Therefore anywhere a file is normally specified we can substitute a program's standard output or input (although process substitution on input is not all that common).
This is particularly useful where a program does not use standard streams for what you want.
Note that in your example you are missing a space, exec >>(tee $LOG_FILE) 2>&1
is wrong (you will get a syntax error). Rather,
exec > >(tee $LOG_FILE) 2>&1
is correct, that space is critical.
So, the exec >
part changes file descriptor 1 (the default), also known as stdout
or standard output, to refer to "whatever comes next", in this case it is the process substitution, although normally it would be a filename.
2>&1
redirects file descriptor 2 (stderr
or standard error) to refer to the same place as file descriptor 1 (stdout
or standard out). Important: if you omit the &
you end-up with a file called 1
rather than successful redirection.
Once you have called the exec
line above, then you have changed the current process's standard output, so output from the commands which follow go to that tee
process instead of to regular stdout
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With