答えとソースコードを比較するシェルスクリプト

作ったもののまとめ

  • シェルスクリプトで実装
  • 写経レベルで一致(順番と書いてある命令、変数名が一致)している場合、間違えているところを出してくれる
    • ただしインデントとコメントは許容する
  • 当然答えファイルが無いと違いが出せない
    • なので教える側用

ソースコードをDIFFしてみた

学校でSAをやっていて、答えのあるソースの写経部分でミスる学生が多かったので、「DIFFで差分出せばどこミスってるかわかるんじゃね?」と思った。 ソースコードも自分の考えを挟まない部分だし、できたら楽だな~とか思いながら$diff seikai.c seito.cとかなんのひねりも無くDIFFしてみた。 しかしインデントが違うので、そこを差分として出してしまうので困った。

空白どうやって無視できるんだろうな~と探してみたらまんまの記事があった。

$ diff -w -B -I '^:space:*#' -I '^:space:*//' a.c b.c

diffで空白を無視する - てきとうなメモ

ありがたやーと思いながら試してみると、こんどはコメント文を入れているいれていないで差分が出てしまう模様。 んん、とりあえずvimでファイル開いて消して~とかやっていたけどvimの機能でなにか消せないかな~と探してみる。

:%s/ # .*//g

Vimでコメント行を全て削除する - yusu-iwasawaのブログ

どうやらこんな感じで正規表現を使えばいいらしい、今回はCのファイルなので、#ではなく//以降を削除するように改変

:%s!//.*!!g

vimで置換の時/しか使えないのかと思ってたら区切り文字選択できるのねあれとか思いつつ、両方のファイルにコメント削除を飛ばしてから実行。

なかなかに的確に差分を出してくれました、間違えのところだけを抽出するのに成功。

これを簡単に作れるように.shに書きしたためたのである。

手打ちをシェルスクリプトに書き換え

とりあえずDIFFはそのままでいいとして、Vimを使っていたのをどうするかである。
まあ、Vim使ってたとはいえ中では置換とそれを別ファイルに保存しかやっていなかったので、これをシェルスクリプトに。

置換

シェルスクリプトで置換はsedを使えばいいらしい。 という事でこんな感じ

cat kotae.c | sed -e 's!//.*!!g' >> temp1.c

標準入力から受け取るらしいので、一回catでファイルの中身を標準入力に流してパイプでつないで、sedの-eで正規表現で置換。 これ自体はvimとほぼ同じなのでコピペコピペ んで、標準出力で出させれるので、こいつをとりあえず適当なファイルへ。

適当なファイルに流すことで二つ目の別ファイルに保存も完了!

実行してみると、置換保存は大丈夫そう

別ファイルに保存

シェルスクリプトにしてみると、実行して終わった後にファイルが残るのはまずかろうと思って、一時的にファイルを作成して消す的なことをしたくなった。
適当な名前をハードコーディングしちゃって後でrm temp.cとかでいいかなと思ったけどそもそも試している環境にtemp.cがあった気がしたので、他とかぶらない一意の名前つけられる機能無いのかなと探してみる。

https://fumiyas.github.io\2013/12/06/tempfile.sh-advent-calendar.html:安全な一時ファイルの作成と削除の方法 - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog

なかなかやる事があるっぽいがとりあえず実装だけしたいということで簡単な方法でささっと実装。 どうやらmktempでファイル作れて、それを変数として保持しといて後で消せばいいらしい。

成果物

どうせ変数使うならとついでに比較対象ファイルも実行時引数で取ってこれるように変更、結果できたのはこんな感じ

#!/bin/sh

tempfile1=$(mktemp)
tempfile2=$(mktemp)

cat $1 | sed -e 's!//.*!!g' >> $tempfile1
cat $2 | sed -e 's!//.*!!g' >> $tempfile2
diff -w -B -I '^[[:space:]]*#' -I '^[[:space:]]*//'  $tempfile1 $tempfile2 | less

rm $tempfile1
rm $tempfile2

とりあえず簡単だけど適当なファイルにコピペして. (スクリプトファイル名) (比較ファイル名) (比較ファイル名)とか入れてあげればlessで差分が表示される。 間違いのあるのファイルでやってみたが、さくっと作ったにしてはちゃんと間違えを示してくれる。

今後やりたいこと

DIFFでコメント無視できる?

記事書いてて思ったけどよく考えたらファイル作成とかしなくてもdiffコマンドでコメントを無視した差分取りできるんじゃないかなとか思った。

web上で動かせるように

使っていたら後輩に
「あとはweb上で動かせるようにするだけですね!」
とか煽られたんで少しやってみたい。 ぶっちゃけどうせ答えファイルを持ってなきゃいけない時点でファイルを動かす動作が必要になるので、webページ完結にしても手間は増えるだけ...

参考にさせていただいた

boscono.hatenablog.com

yusu-iwasawa.hatenablog.com

安全な一時ファイルの作成と削除の方法 - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog