如何制作重定向循环

Mat*_*hid 7 bash io-redirection

这主要是出于学术原因。;-)

考虑以下 Bash 语句:

foo | bar
Run Code Online (Sandbox Code Playgroud)

这将执行两个进程,foobar,这样 的标准输出foo连接到 的标准输入bar。到现在为止还挺好。

有没有办法调用foobar以便我们有相反方向的连接?

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重定向......

PSk*_*cik 4

在 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)