About me | Archives | Tags |
Apr 21, 2020, 19:36 #Tech
独断と偏見ですが、学校で作らされるようなプログラムは、キーボードからの入力に対して出力する対話型のものが多いとおもいます。
オンラインジャッジに提出するプログラムもわりとそういう形式のものが多いですね。
オンラインジャッジは自動でテストケースを実行して結果をおしえてくれます。ローカルでもおなじことができると、学校の課題をやるときとか、典型問題用のテンプレートなんかをつくるときに便利かもな〜とおもってつくってみました。
シェルスクリプトの勉強になりました。
サンプルプログラムとして
というものをつくりました。雰囲気でシェルスクリプトを書いてみます。
サンプルプログラムの実行ファイルは a.out
、テストケースは test01.txt
という形式の連番のファイルです。
#!/bin/bash
list=($(echo `ls test*.txt`))
i=0
while [ -n $list[$i] ]
do
cat $list[$i] | ./a.out
i=`expr $i + 1`
done
シェルスクリプトの配列は
array=(foo bar ...)
で初期化できるので、テストケースを ls
した文字列をつかうだけで配列を準備できます。
ちなみに ls -m -Q
というふうにオプションを指定すると、カンマで区切ってダブルクオーテーションで囲んでくれるので
"foo", "bar", ..., "baz"
と表示してくれます。他の言語でファイルパスを配列にしたいときにつかえるかもしれません。
cat テストケース | ./a.out
で入力を指定して実行します。
実行してみます。
$ ./test.sh
cat: 'test01.txt[0]': そのようなファイルやディレクトリはありません
big
cat: 'test01.txt[1]': そのようなファイルやディレクトリはありません
big
cat: 'test01.txt[2]': そのようなファイルやディレクトリはありません
big
...
while
でバグっています。配列のインデックスを指定してるつもりが、うまくいってません。
たぶん単純に左から評価しているせいで、変数が左から順番に文字列になおされているんでしょう。高級言語じゃないのでしょうがないです。
ということで修正。array[@]
array[*]
で配列の全要素を参照できます。
#!/bin/bash
list=($(echo `ls test*.txt`))
for file in ${list[@]}
do
cat $file | ./a.out
done
実行。
$ ./test.sh
small
even
even
big
odd
even
odd
even
うまくいきました。全部のテストケースの実行結果が表示されています。
しかし、ちょっとこれではエラーが出たときパッとわかりません。
出力が正しいかどうかの情報も表示しましょう。
#!/bin/bash
list=($(echo `ls input*.txt`))
for file in ${list[@]}
do
cat $file | ./a.out |
{
result=$(cat)
buf=${file//input/output}
expectation=$(cat $buf)
if [ $result = $expectation ]
then
echo "<OK> : $result"
else
echo "<NG> : $result"
fi
}
done
パイプで実行結果を result
に格納しています。
この変数は、どうやらブロック {}
で囲まないとスコープ外になって参照できないようです。ちょっとハマりました。
期待される出力を output01.txt
という形式の連番のファイルに入れてあります。番号は入力ファイルとひもづいています。なので、名前を置換して対応する出力ファイルの名前にして expectation
に格納しています。
実行してみましょう。
$ ./test.sh
<OK> : small
<OK> : even
<OK> : even
<OK> : big
<OK> : odd
<OK> : even
<OK> : odd
<OK> : even
うまくいきました。でもなんか味気ないです。もっと瞬間的に把握したい。
五感に訴えかけるため、カラーにしてみましょう。
#!/bin/bash
list=($(echo `ls input*.txt`))
for file in ${list[@]}
do
cat $file | ./a.out |
{
result=$(cat)
buf=${file//input/output}
expectation=$(cat $buf)
id=${file#input}
id=${id%.txt}
if [ $result = $expectation ]
then
echo -e "$id \e[42m OK \e[m \e[32m$result\e[m"
else
echo -e "$id \e[41m NG \e[m \e[31m$result\e[m"
fi
}
done
色を指定して、テストケースの番号も行頭に表示されるようにしました。
実行!
いいですね。
シェルスクリプトは手軽に書けて便利ですね〜。
ただ、高級言語じゃないのでちょっと慣れが必要なのと、動作が OS にけっこう左右されます。
今回は Ubuntu でうごかしていて、シェルは標準の bash です。
それでは。