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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15153158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 23:24:17  来源:igfitidea点击:

How to redirect an output file descriptor of a subshell to an input file descriptor in the parent shell?

bashshellfile-descriptor

提问by user716468

(In BASH) I want a subshell to use a non-STDOUT non-STDERR file descriptor to pass some data back to the parent shell. How can I do that? Eventually I would love to save the data into some variable of the parent shell.

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

EDIT: The subshell runs a black-box program that writes to STDOUT and &3.

编辑:子外壳运行一个黑盒程序,该程序写入 STDOUT 和 &3。

采纳答案by Jan Hudec

BEWARE, BASHISM AHEAD(there are posix shells that are significantly faster than bash, e.g. ash or dash, that don't have process substitution).

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

You can do a handle dance to move original standard output to a new descriptor to make standard output available for piping (from the top of my head):

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

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"
}

Now you should be able to write:

现在你应该可以写:

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

but the <()construct is a bashism. You can replace it with pipeline

但这种<()结构是一种bashism。你可以用管道替换它

run_in_subshell | while read line; do
    process $line
done

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

除了第二个命令也在subshel​​l 中运行,因为管道中的所有命令都可以。

回答by Olaf Dietsche

The easiest way of course, is to capture the output directly in the parent

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

data_from_subshell=$(echo "This is the data I want to pass to the parent shell")

You can use a named pipe as an alternative way to read data from a child

您可以使用命名管道作为从子级读取数据的替代方法

mkfifo /tmp/fifo

now you can redirect the child to /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
) &

and the parent can read from there

父母可以从那里阅读

read data_from_subshell </tmp/fifo


Another way is to use coprocto start a child process. This creates a child with a bidirectional pipe and redirects the child's stdin and stdout to the pipe descriptors. To use both the pipe and stdout in the child, you must duplicate stdout in the parent first

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

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"

Coprocesses were introduced in Bash 4.0.

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