amp*_*ine 13 shell io pipe segmentation-fault
我有一个脚本调用一个程序(特别ttf2afm是 tetex 3.0 的一部分),该程序有时会出现段错误,有时不会。我需要的信息总是在出现段错误之前打印出来,但是我很难阻止管道重定向失败并且在程序失败时不向管道输出任何内容。
我尝试通过 FIFO 重定向,true在最后用括号括起进程,从 shell 函数执行并封装在 中sh -c,但脚本似乎从未让进程输出任何内容,重定向或以其他方式 - 甚至不输出到 stderr。
我知道它能够输出,因为它完全能够从命令行提供它,但由于某种原因不能从脚本提供。
我的问题是,脚本有没有办法忽略程序段错误并给我输出的事实?
我正在运行 BASH 4.1.10(2)-release。
Gil*_*il' 12
程序通常会缓冲其输出以提高效率。也就是说,它们在内存区域(称为缓冲区)中累积输出,并且只有在缓冲区已满或程序中的某些关键点时,它们才会真正将输出输出。当程序正常结束时,它会刷新输出缓冲区(即打印出其中剩余的任何数据)。当它出现段错误时,缓冲区的内容将丢失。
直接在终端中运行程序时您不会观察到这种效果,因为当程序的输出连接到终端(与常规文件或管道相反)时,行为是不同的。在终端中,默认行为是在每行末尾刷新缓冲区。因此,您将看到在程序出现段错误时生成的每一行完整的行。
您可以强制程序在终端中运行并收集其输出。最简单的方法是运行script. 您需要解决许多烦恼:
script 在脚本文件中添加标题行,之后您需要将其删除。script 不返回命令的状态代码,因此如果您想了解段错误或任何其他错误,则需要将其保存在某处。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
Run Code Online (Sandbox Code Playgroud)
经过不断的摸索和摸索,我终于想通了。解决方案有点复杂:
(trap 'true' ERR; exec ttf2afm "$FONT") |
grep ...
Run Code Online (Sandbox Code Playgroud)
显然,exec导致ttf2afm子 shell 进程被捕获的错误接管,导致它在一个无论是否出现段错误都无关紧要的环境中运行。
当程序失败时,捕获全包ERR信号将阻止子 shell 死亡并向主脚本发送信号(如果发生,主脚本将立即终止)。
唯一的问题是,一旦进程出现段错误,内核本身就会将一大堆堆栈跟踪垃圾直接输出到控制台设备,因此没有办法阻止它被输出[据我所知],但这并不重要因为它不影响标准输出或标准错误。