是否可以将文件描述符3重定向到变量?

问题描述

function f()
{
    echo "normal message" >&1
    echo "error message" >&2
    echo "special message" >&3
}

是否可以以完全不重定向stdout和stderr并且文件描述符3的输出存储在变量中的方式调用f?我知道使用临时文件是可能的:

f 3> /tmp/file
variable=$(cat /tmp/file)

但是没有临时文件是否有可能?

解决方法

是否可以以完全不重定向stdout和stderr且文件描述符3的输出存储在变量中的方式来调用f?

不。您不能将文件描述符重定向到变量,因为这样一来,变量内容将不得不在另一个进程执行过程中同时修改为当前shell正在执行的操作。就是您可以使用另一个进程来执行此操作,该进程将从文件描述符读取的数据流式传输到该进程与Shell之间的某个共享内存中,然后Shell在扩展变量时读取该共享内存内容。我相信您可以修补bash来支持这种设置。

但是还是要执行一个函数,而不是对>&3进行硬编码:

log() {
    variable+="$("$@")"$'\n'
}
log echo "special message"

或者更好(或更糟),如果您打算在当前shell中而不是在子shell中执行该过程:

log() {
   logtmpfile=$(tmpfile)
   "$@" > "$logtmpfile"
   variable+="$(<"$logtmpfile")"$'\n'
   rm "$logtmpfile"
}

但是没有临时文件是否有可能?

最好不要。文件是异步进程之间同步的最简单方法。 (有一种hacky-hacky方法,该方法取决于管道exec 3<> >(sleep infinity); echo 123 >&3; timeout 0.1 cat <&3中的缓冲,但是它将以意外的方式失败/阻止。)

,

我刚发现以下语法:

{ variable=$(f 4>&1 1>&3 3>&4); } 3>&1

似乎可以得到我想要的结果。

当然,我的提问方式是:“以完全不重定向stdout和stderr的方式”在这里不适用,但我真正想要的只是在单独的文件描述符上的stdout和stderr。因此,我会将KamilCuk的答案保留为接受状态,但我想将其发布在此处,以防其他人需要。