在Linux中,是否可以连接超过两个标准流到终端?

5

考虑以下简单的程序,并假设它位于名为Test.c的文件中。

#include <stdio.h>

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

假设我将这个程序编译成一个名为Test的可执行文件,并按以下方式运行它。
./Test > Out 2> Err

在此次运行结束后,我将会得到两个文件OutErr,它们分别包含着两条信息。这是很好的,因为我可以有两种不同类型的信息正常地输出到控制台,然后通过使用bash重定向来筛选其中一个或者两个。然而,我只能用两个文件描述符来进行这种类型的筛选似乎非常受限。 是否有某种方法可以打开第三个或更多的文件描述符,使其指向终端输出,以便我可以单独筛选它? 语法可能如下所示。
./Test > Out 2> Err 3> Err2

我猜测 bash 可能会支持这个功能,因为以下测试似乎意味着 bash 会将 & 后面的数字视为文件描述符。
$ ./Test >&2
Hello stdout
Hello stderr
$ ./Test >&3
bash: 3: Bad file descriptor

你的“猜测”是正确的。但是,除非程序知道如何处理打开的fd号码x,否则这只是一个浪费的打开句柄。 - Deduplicator
1个回答

5

在命令行界面,运行以下任意一条命令:

exec 3>/dev/tty

...or...

exec 3>&1

在第一种情况下,会显式地打开文件描述符3,并将其指向您的TTY;在第二种情况下,它会指向stdout当前正在写入的位置。


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

yourprogram --extra-logs-fd=3

如果没有提供这样的选项,则将其输出与stderr组合,或者(根据情况)将其完全禁止。 (想要将额外的日志记录发送到stdout的用户因此可以使用--extra-logs-fd = 1 ,或者对于stderr使用< code> --extra-logs-fd = 2 )。

更好的方法是,如果您的目标操作系统仅限于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模式下你可以做到这一切(在第一个例子中只需将3>extra_logs.txt重定向到你的shell中,在第三个例子中只需使用3> >(tee extra_logs.txt >&2)),但这样会让你手动管理FD号码,有什么好处呢?


1
你可能想使用 fdopen 将此文件描述符包装在 FILE* 流中。 - chqrlie
你可以在程序中打开/dev/tty,但这对用户没有任何好处,因为这样做会阻止他们能够从其shell重定向该流。为了使shell能够控制流所附加的内容,shell需要将流传递到其下面的程序中。 - Charles Duffy
1
@merlin2011,要记住所有的重定向——3>some.log等等——都是在程序运行之前发生的。因此,程序无法改变重定向的语义——它们已经在启动之前完成了! - Charles Duffy
1
@merlin2011,...虽然你的程序可以做一件事情,就是检查是否定义了任何FD 3,如果没有,则将其打开到/dev/null或将stderr复制到其中。但这不是一个好的/安全的做法,因为谁知道环境中的脚本或其他东西是否已经使用该FD号码来实现自己的目的?如果你劫持了它的FDs,你可能会严重破坏调用你的脚本的执行。 - Charles Duffy
@CharlesDuffy,感谢您提供的所有澄清。 - merlin2011
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接