34

(在 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 的黑盒程序。

4

2 回答 2

33

当心,BASHISM AHEAD(有些 posix shell 比 bash 快得多,例如 ash 或 dash,它们没有进程替换)。

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

exec 3>&1 # open 3 to the same output as 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)

但该<()构造是一种bashism。您可以将其替换为管道

run_in_subshell | while read line; do
    process $line
done

except than the second command also runs in subshell, because all commands in pipeline do.

于 2013-03-01T10:06:09.757 回答
6

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

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

另一种方法是使用coproc启动子进程。这将创建一个具有双向管道的子节点,并将子节点的标准输入和标准输出重定向到管道描述符。要在子级中同时使用管道和标准输出,您必须先在父级中复制标准输出

exec 4>&1 # duplicate stdout for usage in client

coproc SUBSHELL (
    exec 3>&1 1>&4- # redirect fd 3 to pipe, redirect fd 1 to stdout
    (
    echo "This should go to STDOUT"
    echo "This is the data I want to pass to the parent shell" >&3
    )
)

exec 4>&- # close fd 4 in parent
read data <&${SUBSHELL[0]}
echo "Parent: $data"

协进程是在 Bash 4.0 中引入的。

于 2013-03-01T09:13:37.330 回答