我正在用 bash 编写一个自动作业评分器。评分者编译一个程序并运行它。如果程序无法编译或无法运行(例如由于分段错误),则等级应该是一个固定的小数字,例如5。否则,等级是程序输出的最后一行。
为了得到最后一行,我可以这样做:
grade=$( ./a.out | tail -1 )
但这总是给出 0 的退出代码,即使 a.out 无法运行(例如未找到),所以我无法判断程序是否无法存在。
另一种选择是使用临时文件:
./a.out > temp
if [ $? -ne 0 ]
then
grade=0
else
grade=$( tail -1 temp )
fi
但是,如果有许多不同的进程同时执行相同的操作,这可能会出现问题。即使使用一个进程,当我只需要最后一行时,将所有输出保留在一个文件中(输出可能很大)也是浪费的。
有没有不使用临时文件的解决方案?
答案1
grade=$( { ./a.out 2>/dev/null || echo 0; } | tail -n 1 )
如果该程序以非零退出状态退出或根本无法执行,这将尝试执行./a.out
,然后在其输出中添加一行。0
会0
被 抓住tail -n 1
并放置在 中$grade
。
如果./a.out
正确执行并以零退出状态终止,则echo
不会被触发。
/dev/null
如果您有兴趣查看与运行相关的诊断消息,请删除标准错误的重定向./a.out
。
更改0
为"$?"
以获取退出代码。为了能够区分数字和错误,您可能需要使用NaN
某些错误字符串。
答案2
您的问题归结为:“我想获取最后一行输出并检测异常退出而不使用临时文件”。在这种情况下,set -o pipefail
就是你的朋友。
这是一个简单的脚本,它执行其参数并在正常退出时记录输出的最后一行:
#!/bin/bash
[[ -x $1 ]] || {
echo >&2 "Usage ${0##*/} <PROGRAM> [ARG1] ..."
exit 1
}
set -o pipefail
program=$1
shift;
x=$($program "$@" | tail -1)
if [[ $? -eq 0 ]]; then
echo "Pass: $x"
else
echo "Fail: $?"
fi
我将把评分的问题留给你。