My question is inspired by this SO answer.
Consider the script:
tmpfile=$(mktemp)
exec 3>"$tmpfile"
rm "$tmpfile"
>&3 cat <<EOS
line 1
line 2
line 3
EOS
cat <&3
You can play with it online here.
I expect it print out the 3 lines, but in fact I get a "Bad file descriptor" error.
Why does the above not work? How can it be altered so that it does?
Note: The error persists even if you delete the 3rd line: rm "$tmpfile"
.
Bad file descriptor; for example, I/O on a descriptor that has been closed or reading from a descriptor open only for writing (or vice versa). There are no child processes. This error happens on operations that are supposed to manipulate child processes, when there aren't any processes to manipulate.
When you don't allow the code to perform the functions related to the file descriptors and the methods used, a Bad File Descriptor Error arises in Python, indicating the wrong way of implementing the code.
In general, when "Bad File Descriptor" is encountered, it means that the socket file descriptor you passed into the API is not valid, which has multiple possible reasons: The fd is already closed somewhere. The fd has a wrong value, which is inconsistent with the value obtained from socket() api.
When bash starts it opens the three standard file descriptors: stdin (file descriptor 0), stdout (file descriptor 1), and stderr (file descriptor 2). You can open more file descriptors (such as 3, 4, 5, ...), and you can close them. You can also copy file descriptors. And you can write to them and read from them.
The command reads (with read ()) from its stdin and gets the data that was written to the pipe by another process. But sometimes the command cannot read from its stdin stream and gets the "Bad file descriptor" error when trying to do so.
“Error: unable to read what child say: bad file descriptor” – Causes & Fixes! In our experience handling website issues, we found 3 main reasons for this “ Error: unable to read what child say: bad file descriptor”. Sometimes, unexpected service crashes can lead to this error.
One possible source of issues is that "stdin" an "stdout" don't correspond necessarily with file descriptors 0 and 1 respectively. In many implementations of the runtime library freopen may change the file descriptor belonging to the FILE*.
I recommend you to use the "open", "close", "dup" etc... system call and deal with file descriptors 0 an 1 directly (or, better, the standard macros STDIN_FILENO and STDOUT_FILENO). Thanks for contributing an answer to Stack Overflow!
You only opened file descriptor 3 for writing, not reading. Change that line to
exec 3<>"$tmpfile"
and the bad file descriptor error will go away.
However, cat <&3
still won't produce any output, because the file pointer is still at the end of the file after the previous write. You would need to seek back to the beginning of the file to output what you just wrote, but bash
doesn't provide a way to seek. The best you can do is reopen the file for reading, either by closing and reopening file descriptor 3 or by opening on another file descriptor.
Since the goal is to read the file after its only link has been removed, you'll have to open another file descriptor for reading before you delete it.
tmpfile=$(mktemp)
exec 3> "$tmpfile"
exec 4< "$tmpfile"
rm "$tmpfile"
>&3 cat <<EOS
line 1
line 2
line 3
EOS
cat <&4
Although 3 and 4 both refer to the same file, they each maintain a separate file pointer. There's no need to open 3 for reading and writing; you can write to the file on descriptor 3, then read the contents from descriptor 4.
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