Bash Closing File Descriptors
Closing file descriptors is the act of releasing a numbered channel once its work is done. A closed number is free for reuse, and a closed input stops feeding a reader.
A closed number is reused by the next open
Descriptor 3 is opened on one file, closed, then opened on a second file. Both files hold their own line, so the reuse worked.
exec 3>first.txt
echo "first file" >&3
exec 3>&-
exec 3>second.txt
echo "second file" >&3
exec 3>&-
cat first.txt
cat second.txtRestore stdout before closing the saved copy
Stdout is saved on descriptor 3, then redirected to a file. Restoring stdout first puts later output back on screen, and closing the copy last keeps the order safe.
exec 3>&1
exec 1>saved.txt
echo "saved line"
exec 1>&3
exec 3>&-
echo "back on screen"
cat saved.txtClose an input descriptor after its loop
The loop reads every line through descriptor 3. Closing it after the loop marks the input as finished.
printf 'one\ntwo\n' > items.txt
exec 3<items.txt
while read -u 3 line; do
echo "got: $line"
done
exec 3<&-
echo "input closed"Example
exec 3>part-one.txt
echo "part one" >&3
exec 3>&-
exec 3>part-two.txt
echo "part two" >&3
exec 3>&-
echo "both parts written"
cat part-one.txt
cat part-two.txtKey points
- Close syntax: use >&- for an output descriptor and <&- for an input descriptor.
- Free numbers: closing frees the number, so a later open can reuse it.
- Close after use: close a descriptor only after its last read or write.
- Restore before closing: restore a saved descriptor before closing its copy, or the saved copy is lost.
- Never close blindly: closing 0, 1, or 2 breaks normal input and output for the rest of the script.
- Close at the end: a loop that reads from a descriptor should close it once the loop finishes.
In this example, descriptor 3 is opened on the first part file and closed after its line is written. The same number is then opened on the second part file and closed after its line. The final lines show both parts, so the close-and-reuse sequence worked.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What happens when a descriptor is closed and then opened again?