在 OSX 上,尝试通过coproc
将服务的 IO 流传递给客户端,将以 bash 脚本实现的服务公开给以 bash 脚本实现的客户端,并以 开始,我发现我可以使用变量 5 和 6,但不能使用 3 和 4 来保存流。我期望能够使用 3 或以上的任何数字。
例如,以下方法有效:
如果./capitalize
服务
#!/usr/bin/env bash
while true; do
read line
echo "${line^}"
done
并且./client
是
#!/usr/bin/env bash
lsof -p $$ | grep PIPE
echo $1 >&6
read line <&5
echo Result: "${line}"
我们检查 bash 版本,启动服务,并反映暴露的管道
$ 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
然后执行
$ ./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
然后事情就会按预期进行。foo
已经大写为Foo
,我们可以看到capitalize
输出和输入流已经重新映射到client
和63 -> 5
。60 -> 6
但是,如果我将文件描述符从 5 改为 3,将 6 改为 4,那么事情就会出乎意料地失败。失败的原因是描述符 3 和 4 没有传递给client
。
如果./client
更新为
#!/usr/bin/env bash
lsof -p $$ | grep PIPE
echo $1 >&4
read line <&3
echo Result: "${line}"
然后执行
$ ./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:
由于文件描述符没有出现,因此没有结果!
那么为什么我可以使用5/6
,但不能使用3/4
? 是3/4
保留的吗? 我怎么知道呢?
另外,如果我使用替代语法进行重定向,那么流就不会被重定向,即使我认为该语法在语义上是等效的。
因此改变这个
$ ./client "foo" 5< /dev/fd/${SVC[0]} 6> /dev/fd/${SVC[1]}
到
$ ./client "foo" 5<&${SVC[0]} 6>&${SVC[1]}
结果是
./client: line 3: 6: Bad file descriptor
./client: line 4: 5: Bad file descriptor
Result:
这两种重定向语法不是5< /dev/fd/${SVC[0]}
应该5<&${SVC[0]}
等效吗?
提前致谢!