Mat*_*hid 7 bash io-redirection
这主要是出于学术原因。;-)
考虑以下 Bash 语句:
foo | bar
Run Code Online (Sandbox Code Playgroud)
这将执行两个进程,foo
和bar
,这样 的标准输出foo
连接到 的标准输入bar
。到现在为止还挺好。
有没有办法调用foo
,bar
以便我们也有相反方向的连接?
foo.stdout -> bar.stdin
foo.stdin <- bar.stdout
Run Code Online (Sandbox Code Playgroud)
据我所知,击调用pipe(2)
以创建一对彼此连接的FD,然后可以用于替换的stdin
/stdout
在相应的子进程。在内核级别,我看不出为什么不能调用pipe(2)
两次并安排上面描述的循环排列。
但我无法弄清楚实际执行此操作的 shell 语法。
到目前为止,我能想到的最好的主意是使用命名管道,或者启动一个子shell并以某种方式进行一些疯狂的FD到FD重定向......
在 bash 中,您可以使用任一coproc来完成此操作(bash 对多个 coproc 的支持很差,但这里只需要一个):
#!/bin/bash
set -e
coproc { while read -r line; do echo "$BASHPID read: $line"; done; }
i=0; while :; do
echo "$BASHPID writing>> $i"
echo $i >&"${COPROC[1]}"
read -r line <&"${COPROC[0]}"
echo "$BASHPID coproc produced>> $line"
i=$((i+1))
done
Run Code Online (Sandbox Code Playgroud)
或命名管道(它们也可以在简单的 POSIX shell 中工作):
#!/bin/bash
set -e
trap 'rm -rf "$tmpd"' EXIT
tmpd=$(mktemp -d)
mkfifo "$tmpd/p0" "$tmpd/p1"
exec 3<>"$tmpd/p0"
exec 4<>"$tmpd/p1"
rm -rf "$tmpd"
( while read -r line; do echo "$BASHPID read: $line"; done; ) <&3 >&4 &
i=0; while :; do
echo "$BASHPID writing>> $i"
echo $i >&3
read -r line <&4
echo "$BASHPID coproc produced>> $line"
i=$((i+1))
done
Run Code Online (Sandbox Code Playgroud)
如果您不习惯在 shell 中处理 fd,那么它们可能看起来都很丑陋。
此外,由于管道对调度的影响(写入具有完整管道缓冲区的管道会阻塞您,就像从具有空管道缓冲区的管道中读取数据一样),您可能会因某些读/写模式而陷入死锁。
上述两个示例的输出可能如下所示:
32435 writing>> 0
32435 coproc produced>> 32441 read: 0
32435 writing>> 1
32435 coproc produced>> 32441 read: 1
32435 writing>> 2
32435 coproc produced>> 32441 read: 2
32435 writing>> 3
32435 coproc produced>> 32441 read: 3
32435 writing>> 4
32435 coproc produced>> 32441 read: 4
Run Code Online (Sandbox Code Playgroud)