出力の最後の行または終了コードを取得する方法

出力の最後の行または終了コードを取得する方法

私はBashで自動宿題採点器を書いています。グレーダーはプログラムをコンパイルして実行します。プログラムがコンパイルまたは実行に失敗した場合(たとえば、分割エラーのため)、評価は5などの固定数字でなければなりません。それ以外の場合、レベルはプログラム出力の最後の行です。

最後の行を取得するには、次のようにします。

grade=$( ./a.out | tail -1 )

ただし、これはa.outを実行できない場合(たとえば見つからない場合)でも常に終了コード0を提供するため、プログラムが存在できないかどうかはわかりません。

別のオプションは一時ファイルを使用することです。

./a.out > temp
if [ $? -ne 0 ]
then
  grade=0
else
  grade=$( tail -1 temp )
fi

ただし、同時に同じ操作を実行する複数のプロセスがある場合、問題が発生する可能性があります。 1つのプロセスを使用しても、最後の行だけが必要なときにすべての出力を1つのファイルに保存するのは無駄です(出力はかなり大きくなる可能性があります)。

一時ファイルを使用せずに回避策がありますか?

答え1

grade=$( { ./a.out 2>/dev/null || echo 0; } | tail -n 1 )

プログラムがゼロ以外の終了状態で終了するか、まったく実行に失敗した場合は、実行を試みて出力に1行を追加し./a.outます。つかまってに配置さ0れます。0tail -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

評価の問題はあなたに任せます。

関連情報