In a shell script, file descriptor 0 stands for stdin, file descriptor 1
stands for stdout, and file descriptor 2 stands for stderr. In addition,
programmers can open, close, or duplicate file descriptors with the
exec
built-in command and the I/O redirection operator:
Syntax | Description |
---|---|
exec $fd< "${filepath}" |
Open an input file at the given file
descriptor $fd |
exec $fd<&- |
Close the input file descriptor $fd |
exec $fd> "${filepath}" |
Open an output file at the given file
descriptor $fd |
exec $fd>&- |
Close the output file descriptor $fd |
exec $dst>&src |
Duplicate the file descriptor from $src
to $dst . Both $dst and
$src will refer to the file which was
referred by $src . |
Example 1: Write some message to another output file
First, open output_file.txt
at file descriptor 3:
exec 3> output_file.txt
Second, redirect the stdout of the command with 1>&3
to print some
messages:
echo 1>&3 "some messages"
Third, close file descriptor 3 with:
exec 3>&-
Example 2: Redirect stdout/stderr temporarily
Under some circumstances, one would like to redirect the stdout or stderr of the subsequent commands. The file descriptor duplication command will be handy in this case.
First, backup stdout and stderr with file descriptor duplication command.
exec 3>&1 # Duplicate stdout to file descriptor 3
exec 4>&2 # Duplicate stderr to file descriptor 4
Second, open files for redirection:
exec 1> stdout.log
exec 2> stderr.log
Third, run the commands as usual:
echo "some output to stdout"
echo 1>&2 "some output to stderr"
Fourth, restore the file descriptors if the shell script still needs them:
exec 1>&3 # Duplicate file descriptor 3 to stdout
exec 2>&4 # Duplicate file descriptor 4 to stderr
exec 3>&- # Close file descriptor 3 (free the resources)
exec 4>&- # Close file descriptor 4 (free the resources)
In this step, first two lines copy the stashed file descriptors back to stdout and stderr. Last two lines close the file descriptors.
Note: Closing a file descriptor does not necessary close a file. If two file descriptors refer to the same file, then the file will not be closed until both file descriptors are closed. In the fourth step, it is important to close file descriptor 3 and 4 to avoid resource leaks.
Example 3: Read lines from a file
First, open an input file with exec
:
exec 3< input_file.txt
Second, read the file with I/O redirection 0<&3
:
while read 0<&3 line; do
echo "GOT: ${line}"
done
Third, close the file with:
exec 3<&-
Reference
- TLDP, Advanced Bash-Scripting Guide, Chapter 20. I/O Redirection
- The Open Group Base Specifications Issue 7, Shell Command Language