🎃

シェルスクリプトで採点を簡単に

2023/10/02に公開

必要な環境

  • bash
  • gcc

実現したいこと

先生目線で学生の提出した(.c)ファイルの採点を効率化したい。
.cファイルをコンパイルして一つ一つ実行していたら日が暮れそうなので、少し効率化出来ないかと考えた。

方法

  1. 学生の提出したファイルを一括ダウンロード(省略)
  2. コンパイルして実行しテキストファイルにリダイレクト
  3. 正しい出力が得られるテキストファイル(模範解答)とdiffをと
  4. diffしたものを再びリダイレクトする
  5. diffファイルのバイト数を調べて0バイトでないものを確認

少しややこしいので次のような問題を考える.

問題設定

問題
"Hello World"と改行を出力する.cファイルを作成しなさい。
ただし、"は出力せず、ファイル名は [学籍番号].c としなさい。
例えば学籍番号9999の人は 9999.c とする。

この問題の模範解答となる出力は当然Hello Worldである。

目標

例えば,Hello World!!!と出力してしまった学生を簡単に検出できるようにしたい。

準備

模範回答の準備

模範解答のソースコードとして次を準備する。

main.c
#include <stdio.h>

int main(void)
{
	printf("Hello World\n");
	return 0;
}

これをコンパイルした後に実行してテキストファイルにリダイレクトする。
これをシェルスクリプトにすると、

$ gcc main.c
$ ./a.out > ans.txt

実際にans.txtの中身は

$ cat ans.txt
Hello World

となる。

また授業履修者のリストをテキストファイルにしたものを用意する。

仮に,学籍番号1111,2222,3333の3人が履修していて課題の提出が確認できていたとする。

$ cat id_list.txt
1111
2222
3333

これを元に繰り返し処理を行う。

## フォルダ構成

フォルダ構成を次のようにして実行してみる。

$ tree -a
.
├── diff         # diffをとったファイルを格納するフォルダ
├── id_list.txt  # 履修者のリスト
├── main.c       # 模範回答を出力するためのソースコード 
├── make_diff.sh # 採点するためのシェルスクリプト
└── src          # 学生の提出したソースコードを格納するフォルダ
    ├── 1111.c 
    ├── 2222.c
    └── 3333.c

## 実行

make_diff.shの中身を次のようにする。

make_diff.sh
gcc main.c
./a.out > ans.txt # 模範解答をリダイレクト

for id in `cat id_list.txt` # 履修者リストを元に繰り返し処理
do
	cd src
	gcc $id.c -o $id
	./$id > $id.txt
	rm $id
	cd ..
	diff ./ans.txt ./src/$id.txt > ./diff/diff_$id.txt # 模範解答とdiffを取る
done

これを

./make_diff.sh

で実行してみる。

権限設定で怒られることがある。

permission denied: ./make_diff.sh

その時は,ターミナルで一度だけ

$ chmod 700 make_diff.sh

と実行してからもう一度./make_diff.shと実行してください。

正しく実行できている場合,実行後は次のようになります。

result
$ tree -a
.
├── a.out
├── ans.txt
├── diff  # 欲しかった結果
│   ├── diff_1111.txt
│   ├── diff_2222.txt
│   └── diff_3333.txt
├── id_list.txt
├── main.c
├── make_diff.sh
└── src
    ├── 1111.c
    ├── 1111.txt
    ├── 2222.c
    ├── 2222.txt
    ├── 3333.c
    └── 3333.txt

2 directories, 14 files

ここで,diffディレクトリでls -lとかすると各ファイルのバイト数が一気に見れる。

$ ls -l
total 8                       # ここ
-rw-r--r--  1 kkml4220  staff   0  4 23 16:17 diff_1111.txt
-rw-r--r--  1 kkml4220  staff  39  4 23 16:17 diff_2222.txt # この人の出力が誤り?
-rw-r--r--  1 kkml4220  staff   0  4 23 16:17 diff_3333.txt

実行環境によってバイト数を表すカラムの場所が違うかもしれないが... 明らかに0でない数字がわかる箇所がある。

となり、学籍番号2222の学生の出力が誤りであると予想できる。

実際にcatで中身を見てみると、

$ cat diff_2222.txt
1c1
< Hello World
---
> Hello World!!!

となっている.よって学籍番号2222の方がHello World!!!と出力しているで誤りということがわかった。

感想

もっと効率化する方法はあるかもしれない。
というかこれはブラックボックステストでしかないため、出力しか見ていないという観点で問題がある。

なので、この方法の問題点を理解した上で実行する分には問題ないかと思う。

より良い方法があればコメントしていただけるとありがたいです。

Discussion