私は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
れます。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
評価の問題はあなたに任せます。