I tried to use the read/write file descriptor in bash so that I could delete the file that the file descriptor referred to afterward, as such:
F=$(mktemp)
exec 3<> "$F"
rm -f "$F"
echo "Hello world" >&3
cat <&3
but the cat
command gives no output. I can achieve what I want if I use separate file descriptors for reading and writing:
F=$(mktemp)
exec 3> "$F"
exec 4< "$F"
rm -f "$F"
echo "Hello world" >&3
cat <&4
which prints Hello world
.
I suspected that bash doesn't automatically seek to the start of the file descriptor when you switch from writing to reading it, and the following combination of bash and python code confirms this:
fdrw.sh
exec 3<> tmp
rm tmp
echo "Hello world" >&3
exec python fdrw.py
fdrw.py
import os
f = os.fdopen(3)
print f.tell()
print f.read()
which gives:
$ bash fdrw.sh
12
$ # This is the prompt reappearing
Is there a way to achieve what I want just using bash?
When you open a file descriptor in bash like that, it becomes accessible as a file in
/dev/fd/
. On that you can docat
and it'll read from the start, or append (echo "something" >> /dev/fd/3
), and it'll add it to the end. At least on my system it behaves this way. (On the other hand, I can't seem to be able to get "cat <&3" to work, even if I don't do any writing to the descriptor).To 'rewind' the file descriptor, you can simply use
/proc/self/fd/3
Test script :
Try to kill -9 the script while it is running, you will see that contrary to what happens with the trap method, the file is actually deleted.
Try changing the sequence of commands:
No. bash does not have any concept of "seeking" with its redirection. It reads/writes (mostly) from beginning to end in one long stream.
I found a way to do it in bash, but it's relying on an obscure feature of
exec < /dev/stdin
which actually can rewind the file descriptor of stdin according to http://linux-ip.net/misc/madlug/shell-tips/tip-1.txt:The write descriptor isn't affected by that so you can still append output to descriptor 3 before the cat.
Sadly I only got this working under Linux not under MacOS (BSD), even with the newest bash version. So it doesn't seem very portable.
As suggested in other answer,
cat
will rewind the file descriptor for you before reading from it since it thinks it's just a regular file.