I am new to shell-scripting and while learning I came across io-redirection & file descriptors. I was reading this document and under the topic Duplicating file descriptors I came across this
[n]<&word
If the digits in word do not specify a file descriptor open for input, a redirection error occurs.
I wanted to test it in my pc so I ran the following simple script
#! /bin/bash
exec 8>'./file.txt'
exec 7<&8
echo 'This should not be printed' >&7
ls -l /proc/$$/fd
exec 7<&-
exec 8>&-
and I expected it to give out an error while duplicating fd7 from fd8 as fd7 was being opened for input from an output file descriptor. Instead of giving an error fd7 was opened with write permissions to the same file fd8 pointed and even printed the echo command onto the file!!
Here is the output on the terminal
total 0
lrwx------ 1 dhruv dhruv 64 Dec 16 12:58 0 -> /dev/pts/0
lrwx------ 1 dhruv dhruv 64 Dec 16 12:58 1 -> /dev/pts/0
lrwx------ 1 dhruv dhruv 64 Dec 16 12:58 2 -> /dev/pts/0
lr-x------ 1 dhruv dhruv 64 Dec 16 12:58 255 -> '/home/fileDescriptors.sh'
l-wx------ 1 dhruv dhruv 64 Dec 16 12:58 7 -> '/home/file.txt'
l-wx------ 1 dhruv dhruv 64 Dec 16 12:58 8 -> '/home/file.txt'
Here is the file.txt
This should not be printed
Can anyone help me on what I am missing, maybe there are changes required in the terminal or any other thing.
It appears the descriptor is not checked as the document says, it's just blindly copied. Here's a variation on the script that uses lsof
to get more details about the FDs:
#! /bin/bash
exec 8>'./file.txt'
echo "After opening for write on unit 8:"
lsof file.txt
exec 7<&8
echo "After copying to unit 7:"
lsof file.txt
echo 'This should not be printed' >&7
read -u7 # this should fail
exec 7<&-
exec 8>&-
And the results (under bash v5.0.3):
After opening for write on unit 8:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
t1 27615 pi 8w REG 179,2 0 3169 file.txt
After copying to unit 7:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
t1 27615 pi 7w REG 179,2 0 3169 file.txt
t1 27615 pi 8w REG 179,2 0 3169 file.txt
./t1: line 11: read: read error: 7: Bad file descriptor
Note that the FD
column lists w
(open for write) for both FDs, rather than r
(open for read) or u
(both). Also, file.txt is successfully written, as you saw.
As stated by @CharlesDuffy in comments, the reason for the blind copying is 3>&4
and 3<&4
are both implemented the exact same way, with an fdup2()
call, not an open()
call. Thus, the copy retains the exact same flags the descriptor it's copied from had, including whether it's opened for read or write.