Bash 如何将子shell的输出文件描述符重定向到父shell中的输入文件描述符?

Bash 如何将子shell的输出文件描述符重定向到父shell中的输入文件描述符?,bash,shell,file-descriptor,Bash,Shell,File Descriptor,(在BASH中)我希望子shell使用非STDOUT非STDERR文件描述符将一些数据传递回父shell。我该怎么做?最后,我希望将数据保存到父shell的某个变量中 ( # The following two lines show the behavior of the subshell. # We cannot change them. echo "This should go to STDOUT" echo "This is the data I want to pass

(在BASH中)我希望子shell使用非STDOUT非STDERR文件描述符将一些数据传递回父shell。我该怎么做?最后,我希望将数据保存到父shell的某个变量中

(
  # The following two lines show the behavior of the subshell.
  # We cannot change them.
  echo "This should go to STDOUT"
  echo "This is the data I want to pass to the parent shell" >&3
)
#...
data_from_subshell=... # Somehow assign the value of &3 of the
                       # subshell to this variable
编辑:
子shell运行一个黑盒程序,将数据写入STDOUT和&3。

当然,最简单的方法是直接在父脚本中捕获输出

data_from_subshell=$(echo "This is the data I want to pass to the parent shell")
可以使用命名管道作为从子级读取数据的替代方法

mkfifo /tmp/fifo
现在,您可以将子对象重定向到
/tmp/fifo

(
    echo "This should go to STDOUT"
    echo "This is the data I want to pass to the parent shell" >/tmp/fifo
) &
家长可以从那里阅读

read data_from_subshell </tmp/fifo

在Bash 4.0中引入了协进程。

当心,前面的BASHISM(有一些posix shell比Bash快得多,例如ash或dash,它们没有进程替换)

您可以执行句柄舞蹈,将原始标准输出移动到新描述符,以使标准输出可用于管道(从我的头顶):

现在,您应该能够编写:

while read line; do
    process $line
done < <(run_in_subshell)

除此之外,第二个命令也在子shell中运行,因为管道中的所有命令都在子shell中运行。

捕获子shell中数据的变量对父shell不可见。使用命名管道时,子shell必须与父shell同时运行(使用&),否则它将在“>/tmp/fifo”处阻塞。在这种情况下需要更多的同步。@user716468当然,我从来没有打算在子shell中捕获数据。我澄清了我的答案。如果你已经知道你的问题的答案,那么你为什么要问这个问题呢?谢谢你的回答和澄清。不,我还没有找到答案。变量方式可能不起作用,因为我希望子shell使用STDOUT打印其他内容,同时将一些数据传递给父级。这里的过程替换还不够吗?您的解决方案非常鼓舞人心!我认为它几乎可以做到这一点。我刚刚提交了对此解决方案的编辑。通过在子shell外部交换&1和&3,我们可以避免更改原始子shell。但是,我不确定您的第二个解决方案(使用|)是否可行,因为管道后的while循环也是BASH中的子shell。@user716468:您必须在子shell中交换&3和&1,因为管道和进程替换都只能取&1。是的,在后期,循环也在子shell中运行。不幸的是,这是非bash的全部功能。这有点痛苦,但由于父脚本和子脚本基本上是等价的,通常您可以将脚本的其余部分移动到管道中的接收命令中。当然,bash解决方案也适用于其他shell,如zsh。但由于性能原因,它在通常用作
/bin/sh
的简单shell中不起作用。bashism免责声明非常有用!“跳把手舞”——我觉得我就是这样打开车门的:我喜欢
exec 3>&1 # creates 3 as alias for 1
run_in_subshell() { # just shortcut for the two cases below
    echo "This goes to STDOUT" >&3
    echo "And this goes to THE OTHER FUNCTION"
}
while read line; do
    process $line
done < <(run_in_subshell)
run_in_subshell | while read line; do
    process $line
done