关于标准输出/标准错误重定向

8
我写了一段代码故意引发运行时错误:
int main()
{
 int a=5;
 printf("Hello World\n");
 printf("a=%s\n", a);
}

它给出:
$ ./error.o
Hello World
Segmentation Fault
$

现在,为了记录运行时错误,我执行以下操作:

$ ./error.o > so.txt
$ ./error.o &> soe.txt

但是这两个文件都是空的。为什么呢?
编辑:
我正在编写一个用于远程编译和执行C程序的脚本。根据我得到的答案,"分段错误"不是程序的错误输出。那么,有没有办法捕获该输出?此外,该程序只是一个样例,因此我无法添加语句。在重定向中是否有其他方法可以进行行缓冲?

1
@Nyan:我故意这么做是为了得到段错误。我正在编写一个脚本来捕获执行错误,所以这只是模仿我脚本可能遇到的输入。 - lalli
1
你编辑了关于如何启用重定向文件的行缓冲的问题。我更新了我的答案以添加这些信息。 - jjrv
3个回答

10

因为在崩溃之前stdout没有被刷新,所以so.txt文件是空的,因为缓冲区的内容丢失了。如果在printf命令之间添加fflush(stdout)代码,它将包含预期的文本。

您的soe.txt文件也缺少“Segmentation Fault”消息,因为它是由shell打印的,而不是由程序打印的,因此没有成为程序输出的一部分,也没有被重定向。

如果您无法修改代码,可以通过欺骗程序认为正在打印到tty来打开行缓冲。创建名为error.sh的脚本:

#!/bin/sh
./error.o

然后在Linux上执行chmod a+x error.sh并这样调用它:

script soe.txt -c ./error.sh

或者在 Mac OS X 上这样做:

script soe.txt ./error.sh

输出结果可能因系统而异,但通常会包含"Hello World"和"Segmentation Fault"。

还要考虑添加适当的#include行并从main函数中返回值。


有没有一种方法可以在文件中捕获“分段错误”?我可以在bash内运行另一个bash并这样做吗? - lalli
实际代码中也包含了 #include 和 return。我只是在这里打字而不是复制粘贴,所以忘记了这些东西... - lalli

7
因为分段错误是一件严重的事情。缓冲区不会被刷新,你的进程只会被强制关闭。
当你在没有重定向的情况下运行时看到文本的原因是标准输出是行缓冲的(ISO C规定只有在确定设备不是交互式设备时才使用完全缓冲)。换句话说,在无效的反引用之前,它将在看到换行符时刷新。
但由于文件输出不是行缓冲的,当程序的宇宙从其下面拔出时,信息仍在等待发送。
尽管对此的支持是实现定义的,但你可以使用setvbuf和_IOLBF模式设置特定的文件句柄为行缓冲,类似于:
setvbuf (stdout, NULL, _IOLBF, BUFSIZ);

main()的开始处 - 这可以节省大量的打字时间,而不必在每个输出行上使用fflush

有没有一种方法可以使用重定向缓冲行? - lalli
@lalli,可以的,我经常这样做来避免到处放置“fflush()”。请参考setvbuf()的更新。 - paxdiablo

3
我认为这应该可以解决问题:
echo ./error.o | sh > error.txt

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