シェルスクリプトの開発環境

モダンとまではいかなくてもシェルスクリプトの開発環境ってみんなどうしてるのかなあと思う今日この頃。

今はHiveでデータをうごうごいじったりするのにシェルスクリプト使っているんだけどなんだかスクリプト地獄になってきている気がするんだよなあ。

前の現場でもスクリプト書いたので開発環境周りを書いてみたいと思います。


その前にありがちな状況としては、


1. サーバー上で直接ソース編集
 ローカルはWindowsだしねー

2. バージョン管理無し
 ファイル、フォルダ名に日付つけて管理

3. 自動テスト無し
 軽く動作確認すればOKでしょ

4. CI無し
 ナニそれおいしいの


あたりでしょうか。10年前のWebアプリ開発みたいですねw

まあシェルスクリプトって割と書き捨てだし、環境依存多いし、小物系だから、一人でちょちょっとやる分には上記でもそんなに問題無かったりします。

とはいえ複数人で作業する場合とかに問題が出てくる可能性がありますので、もう少し整備したほうがいいでしょう。

まずは1ですが、仮想化全盛の時代ですしVM使うのがいいでしょう。僕はVirtualBox使ってます。VirtualBox上のCentOSVimでソース編集してます。ちなみにデバッグはsh -xとかしてます。

次に2ですが、バージョン管理ソフトはやはり使いましょう。そうすれば気楽に削除できるので無駄なファイルが無くなってすっきりします。バージョン管理ソフトはいまどきならGitのようなDVCSかもしれませんが、僕はSVN使ってます。まだそういう現場も多いでしょう。

コミットはLinuxではTortoiseSVNが無いこともありコマンドで行います。

とはいえ環境の問題でサーバー上で直接ソース編集することもあるかもしれません。僕の直近の例でいうとHiveでデータを取り出したりするんですが、データ量が多くHadoopクラスタで実行しても数分かかります。VirtualBox上では擬似分散環境ですのでデータ量を絞らないと実行時間が長くかかりすぎてしまいます。なので直接サーバー上でソース編集して動作確認することもあります。このあたりはどこまで開発環境(この例ではVM)を頑張って作るかという話になります。

で、それはともかくサーバー上で直接ソース編集してコミットできればいいですが、SVNが入ってないとかでコミットできないかもしれません。

その場合はローカルにWinSCPとかで持ってきてTortoiseSVNとかでコミットすることになります。面倒ですねw

その場合の注意点としてはWindowsLinuxの環境をいったりきたりするので、改行コードとか実行権限とか気にする必要があります。改行コードがCRLFで実行するとbad interpreterとか言われますしね。

ていうか気にしないようにsvn:eol-styleとsvn:executableが自動でつくようにしたほうがいいでしょう。これでチェックアウトしたときにOSにあわせた改行コードになり実行権限もつきます。

Subversionの設定ファイル(Linuxなら~/.subversion/config)で以下のようにenable-auto-propsと*.shのコメントを外します。

### Set enable-auto-props to 'yes' to enable automatic properties
### for 'svn add' and 'svn import', it defaults to 'no'.
### Automatic properties are defined in the section 'auto-props'.
enable-auto-props = yes

### Section for configuring automatic properties.
[auto-props]
### The format of the entries is:
###   file-name-pattern = propname[=value][;propname[=value]...]
### The file-name-pattern can contain wildcards (such as '*' and
### '?').  All entries which match will be applied to the file.
### Note that auto-props functionality must be enabled, which
### is typically done by setting the 'enable-auto-props' option.
# *.c = svn:eol-style=native
# *.cpp = svn:eol-style=native
# *.h = svn:eol-style=native
# *.dsp = svn:eol-style=CRLF
# *.dsw = svn:eol-style=CRLF
*.sh = svn:eol-style=native;svn:executable
# *.txt = svn:eol-style=native
# *.png = svn:mime-type=image/png
# *.jpg = svn:mime-type=image/jpeg

3の自動テストですが、シェルスクリプトではshunit2というテスティングフレームワークがあります。

http://code.google.com/p/shunit2/

これについては以前少し書きましたね。
シェルスクリプトのユニットテスト - wyukawa’s blog

サンプルテストコード

#! /bin/sh
# file: examples/equality_test.sh

testEquality()
{
  assertEquals 1 1
}

# load shunit2
. ../src/shell/shunit2

実行結果

testEquality

Ran 1 test.

OK

それなりに使えます。

シェルスクリプトはファイル整形が多いのでテストデータの管理は考える必要がありますね。

ディレクトリ構成はこんな感じですかねえ。この辺は考え中です。テストケースごとにテストコード、テストデータ、期待値データをひとつのディレクトリにまとめるでもいいかも。

src/
  shell/ プロダクトコード置き場
    example.sh プロダクトコード
  test/ テストコード置き場
    example_test.sh テストコード
    input/ テストデータ置き場
      001/ テストケースID
        input.dat テストデータ
    expected/ テスト結果の期待値データ置き場
      001/ テストケースID
        expected.dat 期待値データ


4のCIですが、Jenkinsでテスト実行はできると思いますがやったこと無いですね。shunit2の結果を読み込むようなプラグインも無さそうだし、そもそもあんまテスト書かなかったりするし(汗

でもテストじゃないけどJenkinsでチェックアウトしてシェル実行は試してみましたが、わりといい感じです。実行ログ見れますしね。

流れとしてはVM上でソース編集して動作確認→コミット→Jenkinsのビルド実行ボタン押す→ブラウザ上で結果確認という感じですね。

こんなもんかな