On OSX, while attempting to expose a service implemented as a bash script, and started with coproc
, to a client implemented as a bash script, by passing the IO streams of the service to the client, I discovered I could use variables 5 and 6, but not 3 and 4 to hold the streams. I expected to be able to use any number 3 or above.
For example, the following works:
If service ./capitalize
is
#!/usr/bin/env bash
while true; do
read line
echo "${line^}"
done
and ./client
is
#!/usr/bin/env bash
lsof -p $$ | grep PIPE
echo $1 >&6
read line <&5
echo Result: "${line}"
and we check our bash version, start the service, and reflect on the exposed pipes
$ bash --version
GNU bash, version 5.0.18(1)-release (x86_64-apple-darwin19.5.0)
$ coproc SVC { ./capitalize; }
$ echo ${SVC[@]}
63 60
$ lsof -p $$ | grep PIPE
bash 30833 Setup 60 PIPE 0xaafc4e53240e4cbe 16384 ->0x1eca6ceb32d18709
bash 30833 Setup 63 PIPE 0x904d6242c4e8c148 16384 ->0xe8caffae10f9dd84
and then execute
$ ./client "foo" 5< /dev/fd/${SVC[0]} 6> /dev/fd/${SVC[1]}
bash 31441 Setup 5 PIPE 0x904d6242c4e8c148 16384 ->0xe8caffae10f9dd84
bash 31441 Setup 6 PIPE 0xaafc4e53240e4cbe 16384 ->0x1eca6ceb32d18709
Result: Foo
then things behave as expected. foo
has been capitalized to Foo
and we can see the capitalize
output and input streams have been re-maped into client
as 63 -> 5
and 60 -> 6
.
However, if I change the file descriptors from 5 -> 3 and 6 -> 4, then things unexpectedly fail. They fail because descriptors 3 and 4 do not get passed to client
.
If ./client
is updated to
#!/usr/bin/env bash
lsof -p $$ | grep PIPE
echo $1 >&4
read line <&3
echo Result: "${line}"
then executing
$ ./client "foo" 3< /dev/fd/${SVC[0]} 4> /dev/fd/${SVC[1]}
./client: line 3: 3: Bad file descriptor
./client: line 4: 4: Bad file descriptor
Result:
yields no results because the file descriptors do not appear!
So why can I use 5/6
, but not 3/4
? Are 3/4
reserved? How would I know that?
Also, if I executing using an alternate syntax for redirection then the streams are not redirected even though I thought the syntax where semantically equivalent.
So changing this
$ ./client "foo" 5< /dev/fd/${SVC[0]} 6> /dev/fd/${SVC[1]}
to
$ ./client "foo" 5<&${SVC[0]} 6>&${SVC[1]}
results in
./client: line 3: 6: Bad file descriptor
./client: line 4: 5: Bad file descriptor
Result:
Aren't those two syntaxes for redirection, 5< /dev/fd/${SVC[0]}
and 5<&${SVC[0]}
supposed to be equivalent?
Thanks in advance!
grep
forFIFO
, hardly relevant; anyway there is noBad file descriptor
for3
nor4
, these descriptors work as well as5
and6
). The other issue is a separate issue.