Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explain the bash command "exec > >(tee $LOG_FILE) 2>&1"

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 ?

like image 258
Yves Avatar asked Mar 27 '18 09:03

Yves


People also ask

What is the exec command in bash?

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.

What does tee mean in bash?

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.

What does the tee command do?

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.

How does exec command work?

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.


1 Answers

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.

like image 56
cdarke Avatar answered Oct 17 '22 16:10

cdarke