如何获取最后一行输出或退出代码

如何获取最后一行输出或退出代码

我正在用 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,然后在其输出中添加一行。00被 抓住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

我将把评分的问题留给你。

相关内容