「技評×オングスこんなシェルスクリプトは書いちゃダメだ!」に参加してきました

技評×オングスこんなシェルスクリプトは書いちゃダメだ!」に参加してきました

技評×オングスこんなシェルスクリプトは書いちゃダメだ!に参加してきました。FreeBSD勉強会を開催している@daichigotoさんが主催されています。FreeBSD勉強会は若干お堅い内容なので、もう少しカジュアルな内容の勉強会にしたいとのことです。

シェルスクリプトの3つの側面

シェルスクリプトには以下の3つの側面があるとのことです。

  • システムを組み上げるためのソフトウェア
  • ユーザが操作するインタフェース
  • 業務システムを組み上げるためのソフトウェア

シェルスクリプトはエンジニアの腕前の差がはっきりと出るものであり、学ぶことによって効率のよいシェルスクリプトが書けるようになるということ、また、シェルとカーネルをよく知るエンジニアが書くスクリプトは効率がよい処理になるという説明がありました。

ポイントとしては"at a glance"(一瞥してわかる)な書き方が重要とのことです。
(私の英語力はまったくダメダメなので思わず辞書を引いてしまいました……)

ダメなスクリプトの例

ダメなスクリプトの例として以下が挙げられていました。

手続き型的な発想のシェルスクリプト

手続き型的なプログラミングでは、データに対する順次処理を書いてしまいがちですが、「まず最初に処理するデータを減らす」ことが重要とのことで、悪い書き方と良い書き方として、以下のような例が示されていました。

  • (悪い書き方)データレコードの各フィールドを都度if文でチェックしてから集計する方法
  • (良い書き方)awkでマッチする行を抜き出してから集計する方法

前者と後者では1000倍くらい速度が違うという結果を示しながらの説明となっていました。料理でも下ごしらえが重要だったりするので、データ処理においても下ごしらえに相当する処理をどうするかは重要なのだなと思いました。

変数を多用するシェルスクリプト

シェルスクリプトの変数展開は遅い処理であるという説明がありました。例として文字列の連結をシェル変数上で行った場合とファイルに追加出力した場合の結果が示されていました。

私の環境でもちょっと試してみました。26Kbyteほどのテキストファイルに対して先の手順を実施してみます。

$ w3m -dump http://www.aozora.gr.jp/cards/000081/files/4601_11978.html > furandon.txt
$ ls -hl furandon.txt
-rw-r--r--  1 fpig  users   26K Sep  2 04:49 furandon.txt

結果は以下となりました。データサイズが小さいとはいえ、すでに10倍程度の速度差が出ています。数メガ、数ギガ単位のデータであれば、見過ごせないほどの速度差になってくるはずです。

$ # シェル変数上で文字列連結した場合
$ time (cat furandon.txt | while read i; do a=$a$i; done)

real    0m1.348s
user    0m1.047s
sys     0m0.031s

$ # ファイルに追加出力した場合
$ time (cat furandon.txt | while read i; do echo $i >> out.txt; done)

real    0m0.124s
user    0m0.040s
sys     0m0.053s

関数(ただし、これは場合によりけりのようです)

これはシェル変数のスコープに関連してくる話で、シェルスクリプト関数の実態はグルーピングした処理であるため、文脈によってグローバルな変数を書き換えてしまう、という話でした。ただ、これは必ずしも悪手というわけではなく、シェルスクリプトの振る舞いをよく理解せずにコードを書くとハマる可能性があるよ、という意味での説明のようでした。

なぜこんな仕組みになっているのか?

シェルスクリプトのダメな例/良い例の話があった後、なぜこんな仕組みになっているのかの説明がありました。

シェルスクリプトの深い部分を理解しようと考えた場合、それはOSレイヤに踏み込んで行く形になります。取っ掛かりとして、シェルと結びつきが強い以下のシステムコールがどういう振る舞いをするか把握するとよいとのことでした。

  • fork(2)
  • execve(2)
  • pipe(2)
  • wait3(2)

ちょっと興味があったので、別エントリでNetBSDでの場合を調べてみました。

シェルによるシステム開発方式

一通り「こんなシェルスクリプトは書いちゃダメだ!」という説明があった後、株式会社オングスさんで実践しているttt開発方法を例にしたシェルによるシステム開発方式の説明がありました。

どのシステム開発にも言えることだと思いますが、シェルによるシステム開発でもうまく行くパターンと失敗するパターンがあるようです。

うまく行くパターンとしては、開発するシステムに対する業務フロー図やER図がちゃんと記述できること(記述できないということは、どんなシステムにするかを明確化できていない)、データの配置が事前に考えられているころ、UIにはHTML5/CSS3アダプティブデザインなど、最新の技術が活用されていることや、バックエンド側は長くても数百行程度のシェルスクリプトになっていること等が挙げられていました。

上記のパターンと逆の状態になっているケースが、いわゆる失敗するパターンとして説明されていました。

スキルアップのための書籍やサイト

これからシェルスクリプトやシェルによる開発を始めてみようという人向けに、以下の情報源が提示されていました。

次回の勉強会について

今回の勉強会は満員ということもあり、次回の開催も決定しています!とのことです。

また、FreeBSD勉強会が今月中頃に開催されます。

参加者からの質問

参加者から出た質問については、シェルスクリプトデバッグ手法に関する内容が多かった気がします。また、BSD系OSをこれから使ってみようと考えている方もおられたようで、BSD人気を増やす向きの勉強会はありがたいものです。

シェルのデバッグ手法としては、シェバンに"/bin/sh -exv"を指定する方法、パイプの途中をteeで眺める方法などが紹介されていました。

他にもシェル変数の意味(「$$」など)の意味をどう調べたらよいか(man shに説明があるようですが、もう少しカジュアル(?)な変数の意味リストが欲しいかと……)、といった質問や、jsonやpdf等のデータをシェルスクリプトで扱う方法(オングスさんではズバリjsonというコマンドを用意しているそうです)といった質問が出ていました。

まとめ

技評×オングスこんなシェルスクリプトは書いちゃダメだ!に参加してきました。シェルスクリプトは日々の小さな作業をパッとこなすために使っており、大きなシステムを作ったことはなかったのですが、この勉強会の内容を元に比較的大きなシステムを手早く作れるようになれれば良いなと思います。