是否可以将两个以上的标准流连接到 Linux 中的一个终端?

Is it possible to connect more than the two standard streams to a terminal in Linux?

考虑以下简单程序,假设它位于名为 Test.c.

的文件中
#include <stdio.h>

int main(){
    fprintf(stdout, "Hello stdout\n");
    fprintf(stderr, "Hello stderr\n");
}

假设我将这个程序编译成一个名为 Test 和 运行 的可执行文件,如下所示。

./Test > Out 2> Err

在此运行 之后,我将有两个文件OutErr,它们将分别包含这两个消息。

这很棒,因为我通常可以将两种不同类型的消息打印到控制台,然后使用 bash 重定向过滤其中一种或两种。然而,我只能用两个文件描述符进行这种过滤这一事实似乎非常有限。

有什么方法可以打开第三个或第 n 个文件描述符,指向终端输出,以便我可以单独过滤它?

语法可能是这样的。

./Test > Out 2> Err 3> Err2

我推测 bash 可能对此有一些初步的支持,因为下面的测试似乎暗示 bash 会将 & 之后的数字视为一个文件描述符。

$ ./Test >&2
Hello stdout
Hello stderr
$ ./Test >&3
bash: 3: Bad file descriptor

在 shell、运行

exec 3>/dev/tty

...或...

exec 3>&1

...将打开文件描述符 3,将其明确指向您的 TTY(在第一种情况下),或指向 stdout 当前正在写入的位置(在第二种情况下)。


如果你想在程序中使用它,我强烈建议将一个 FD 号码作为一个可选参数来写入额外的日志:

yourprogram --extra-logs-fd=3

...将该输出与 stderr 组合,或者如果没有给出此类选项,则完全(视情况而定)将其抑制。 (想要将额外日志记录转到 stdout 的用户因此可以使用 --extra-logs-fd=1,或 --extra-logs-fd=2 作为 stderr)。

更好的是,如果您的唯一目标 OS 是 Linux,则只需接受要写入的文件名:

# to write to a file
yourprogram --extra-logs=extra_logs.txt

# to write to FD 3
yourprogram --extra-logs=/dev/fd/3

# to write to a tee program, then to stderr (in ksh or bash)
yourprogram --extra-logs=>(tee extra_logs.txt >&2)

...当然,您 可以 使用 FD 模式完成所有操作(在第一种情况下,只需在 shell 中重定向 3>extra_logs.txt,和3> >(tee extra_logs.txt >&2)在第三个),但这让你手工完成管理FD号码的工作,有什么好处?