段故障处理程序的管道输出


13

我有一个脚本,该脚本调用ttf2afm有时会出现段错误而有时没有的程序(特别是tetex 3.0的一部分)。我需要的信息总是在段错误之前被打印出来,但是我很难阻止管道重定向失败,并且在程序失败时不向管道输出任何内容。

我尝试过通过FIFO进行重定向,true最后用a括住该过程,从shell函数执行并封装在中sh -c,但是脚本似乎从未允许该过程输出任何东西,无论是重定向还是以其他方式输出-甚至不输出到stderr。

我知道它能够输出,因为它完全有能力从命令行提供它,但是出于某种原因却不能从脚本中提供。

我的问题是,脚本是否可以忽略程序段错误并给我输出的事实?

我正在运行BASH 4.1.10(2)-发行版。

Answers:


12

程序通常会缓冲其输出以提高效率。也就是说,它们将输出累积在一个存储区(称为缓冲区)中,并且只有在缓冲区已满或程序中的某些关键点时,它们才实际输出输出。程序正常结束时,它将刷新输出缓冲区(即打印出其中剩余的任何数据)。当它出现段错误时,缓冲区的内容将丢失。

当直接在终端中运行程序时,您不会观察到这种效果,因为当程序的输出连接到终端(与常规文件或管道相对)时,行为是不同的。在终端中,默认行为是在每一行的末尾刷新缓冲区。因此,您将看到程序段出现故障时所产生的所有完整行。

您可以强制程序在终端中运行并收集其输出。最简单的方法是运行script。您需要解决许多烦恼:

  • script 在脚本文件中添加标题行,之后您需要将其删除。
  • script 不会返回命令的状态码,因此,如果您想了解segfault或任何其他错误,则需要将其保存在某处。
  • script会导致正常输出并输出错误;您最好将错误输出保存到单独的文件中。
export FONT="foo"
script -q -c '
    ttf2afm "$FONT.ttf" 2>"$FONT.ttf2afm-err";
    echo $? >"$FONT.ttf2afm-status"
' "$FONT.ttf2afm-typescript"
tail -n +2 <"$FONT.ttf2afm-typescript" >"foo.afm"
rm "$FONT.ttf2afm-typescript"
if [ "$(cat "$FONT.ttf2afm-status")" -ne 0 ]; then
  echo 1>&2 "Warning: ttf2afm failed"
  cat "$FONT.ttf2afm-err"
fi

是否没有更优雅的解决方案,例如将输出缓冲区设置为0的某些shell设置?
amphetamachine

4

我终于通过反复试验的过程弄清楚了。解决方案有点令人费解:

(trap 'true' ERR; exec ttf2afm "$FONT") |
grep ...

显然,exec导致ttf2afm错误的原因是接管子Shell进程的原因,从而导致该子进程在段故障无关紧要的环境中运行。

捕获所有包含的ERR信号将阻止子shell死亡,并在程序失败时将信号发送到主脚本(如果确实如此则立即终止)。

唯一的问题是,一旦进程出现段错误,内核本身直接将大量堆栈跟踪垃圾输出到控制台设备,因此没有办法阻止其输出(据我所知),但这没关系因为它不会影响stdout或stderr。


3
我很高兴这对您有用,但是我可以自信地说它起作用的原因不是因为bash将输出缓冲区的大小设置为0 ttf2afm。我想知道(trap true ERR; exec ttf2afm "$FONT")| …行为方式如何与有所不同ttf2afm "$FONT" | …
吉尔(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.