将进程替换的文件描述符放入变量中

将进程替换的文件描述符放入变量中

我有很长的命令,大致是这样的:

$ command-outer "long command which references a file here: filename1, and another file reference here: filename2"

这些文件是另一个命令的输出。所以我正在做:

$ command-outer "long ... "<(command-inner "again long params")"...  "\
  <(command-inner "again long params")" ..."

为了便于阅读,我想<()从长命令调用中提取内部未命名/匿名管道(带有 的管道)。但我似乎不能这样做;执行以下操作:

RESULT_FILE_DESCRIPTOR1=<(command-inner ....)

RESULT_FILE_DESCRIPTOR1导致当我实际在参数列表中使用时文件描述符已经被关闭command-outer

command-outer在同一行调用,因此:

    RESULT_FILE_DESCRIPTOR1=<(command-inner ....) outer-command "long ... $RESULT_FILE_DESCRIPTOR1 ... "

返回一个空结果 RESULT_FILE_DESCRIPTOR1,这并不奇怪,因为:

FOO=BAR echo $FOO

也不起作用。

答案1

您可以只命名命令,而不是命名结果。

param_set_1(){
    input_command \
        -lots     \
        -of       \
        -params
}
param_set_2(){
    input_command \
        -lots     \
        -of       \
        -other    \
        -params
}

command_outer -params <(param_set_1) <(param_set_2)

您还可以经常按名称引用文件描述符。

param_set_1 | { param_set_2 | command_outer -params /dev/fd/3 -; } 3<&0

如果您确实想要当前 shell 变量中的结果在文件描述符中,那么你应该避开管道。您冒着用命令的输出填充管道缓冲区的风险,同时尝试将这些结果分配给父 shell 变量,然后管道缓冲区可以被读取过程耗尽......好吧,这并不漂亮。因此,您应该一次性完成所有内容,并使用此处文档。

unset fd3 fd4
{   command_outer -params /dev/fd/[34]
}   3<<FD3 4<<FD4
${fd3=$(param_set_1)}
FD3
${fd4=$(param_set_2)}
FD4

答案2

您可以显式使用命名管道(我认为进程替换确实在细节中使用了命名管道):

trap cleanup EXIT
cleanup() { rm -f "$inner1" "$inner2"; }

inner1=$(mktemp -u) && mkfifo "$inner1"
command-inner "again long params" > "$inner1" &

inner2=$(mktemp -u) && mkfifo "$inner2"
command-inner "again long params" > "$inner2" &

command-outer "long ... $inner1...  $inner2 ..."

相关内容