我运行了一个可执行文件bash
./code > log
它在终端上偶尔显示错误消息,而所有 printf 语句都会进入日志文件。我像下面一样重新运行它
./code >& log
现在,偶尔的错误消息也会记录到日志中。但如果存在分段错误,它仍然会显示在终端上。为什么?如何使消息Segmentation fault (core dumped)
进入日志文件?
用户$ bash --版本
GNU bash,版本 4.2.24(1)-release (i686-pc-linux-gnu)
答案1
“分段错误”消息被打印到 stderr,但它是 shell 的标准错误,而不是程序的标准错误。当 shell 检测到程序因信号而终止时,它会打印此消息。
您可以通过在运行程序的 shell 脚本部分周围重定向 stderr 来静默该消息:
{ ./code; } >&log
答案2
分段错误是一个信号,如果您没有捕获它,那么您的程序将被终止,并且您的 shell 会将其打印到其 stderr(而不是您程序的 stderr)。
发生这种情况时,您的程序或 shell 可能会采取特定操作,方法是让程序捕获信号,或者您的 shell 捕获 SIGCHILD 信号,然后检查子进程的退出状态。
答案3
错误消息会被重定向,但如果存在分段错误,则仅显示在终端上。为什么?
根据 Giles 的 TL/DR:分段错误消息不是来自程序的stderr
或stdout
,因此重定向这些消息没有效果。分段错误消息由运行分段错误子进程的 shell 生成。
幕后发生的事情是,子进程死亡后,shell 调用wait()
(或waitpid()
) 并使用其响应来确定子进程是否因收到信号而死亡。
如果是这样,shell 通常会打印一条消息,但并非总是如此。
请注意,shell 不会神奇地以某种方式发出trap
杀死孩子的信号。只有孩子才能捕捉到信号,或者被信号杀死。当孩子死亡时,父母会收到一个 SIGCHLD,但这是一个不同的信号。
除了打印或不打印错误消息之外,shell 还设置$?
指示退出状态。
$ ./div_by_0
Floating point exception
$ echo $?
136
这同样适用于除以零和其他信号。请参阅man 3 wait
了解完整详细信息。
这样做的一个后果是,只有当子进程是进程链中的最后一个时,您才会收到消息。
例如
$ ./div_by_0
Floating point exception
$ echo | ./div_by_0
Floating point exception
$ ./div_by_0 | wc
0 0 0
根据 Giles 的说法,将命令的输出捕获到文件中并不会阻止 shell 打印消息。
$ { ./div_by_0 ; } > log
Floating point exception
$ { ./div_by_0 ; } >& log
$ cat log
Floating point exception
但是,将命令的输出捕获到变量中确实会阻止 shell 打印消息。
$ a=$(./div_by_0)
$ echo $a
$
捕获输出,无论是到变量还是文件中,都不会阻止$?
被设置。
$ { ./div_by_0 ; } >& log
$ echo $?
136
$ a=`{ ./div_by_0 ; }`
$ echo $?
136
根据您想要对错误消息执行的操作,上述内容可能已经满足您的需求,或者您可能希望$?
在调用程序后进行检查。
您还可以用来trap ERR
捕获错误,然后调用行为来检查是否$?
匹配 SIGSEGV 或 SIGFPE 或其他内容。
例如
$ trap 'exit_code=$?; echo "exit code: $exit_code"; if [[ $exit_code -eq 139 ]]; then echo "segfault"; fi ; if [[ $exit_code -eq 136 ]] ; then echo "div by 0"; fi ;' ERR
$ ./div_by_0
Floating point exception
exit code: 136
div by 0
请注意,如果您trap
打开SIGCHLD
,您的陷阱代码将在$?
设置之前被调用,这不太可能是您想要的。错误命令将显示为返回“$?” = 0,而以下命令将显示返回非零$?
例如
$ ./div_by_0
exit code: 0
Floating point exception
$ ./div_by_1
exit code: 136 <-- this is $? from div_by_0, not from div_by_1
div by 0