ポータブルなシェルスクリプトを書く - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog

2013-12-19(Thu) [sh][shell] [更新履歴]

拡張 POSIX シェルスクリプト Advent Calendar 2013、19日目の記事です。 うおー、あと 30分で書かないといけねー! 雑な内容ですみません。

今日はポータブルなシェルスクリプトの書き方ついてざっくり語ります。 UNIX 系 OS であれば大抵の OS / バージョンでも動くシェルスクリプト!! (ただし外部コマンドの非互換性の問題は除く)

#!/bin/sh で書く

POSIX sh でスクリプトを書けば完璧! shebang は #!/bin/sh!!

…全然完璧ではありません。Solaris 10 のように /bin/sh が POSIX sh でない残念な OS がまだ生き残っています。 マニュアルにも載っているバグが仕様になったのではないかと思われる謎挙動や未知のバグを回避するのが大変です。

ポータブルにするには #!/bin/sh はまだ推奨できません。

#!/bin/ksh で書く

ksh いいよ、ksh…。

何がいいかというと、大抵の商用 UNIX にデフォルトでインストールされています。 それ以外の Linux 系 OS などではデフォルトでは入っていないことが多いようですが、 大抵はコマンド一発でインストールされます。

ただし問題が 2つ。

問題一つ目。 ksh には大きくわけて 2つのバージョン、ksh 88 と ksh 93 があります (数字はリリースされた西暦下二桁)。 大きな違いは ksh 88 が連想配列をサポートしていない点ですが、 ほかにも色々と ksh 93 で拡張された機能があります。 よって、ポータブルにするには ksh 88 縛りにすることを推奨します。 ksh バージョン間の違いを把握するのが難しいようであれば、 POSIX sh 縛りで書けば(大抵は?)問題ありません。

問題二つ目目。 あれ、何だったっけ? 思い出したら追記します…。 ksh のクローンの一つ、mksh (とその源流 pdksh) の互換性が微妙って話だったっけ? mksh ではなく AT&T 派生の正統な ksh を使用しましょう。

#!/bin/bash で書く

私、最近、Linux 向けの仕事しかしていません。 Linux と言えば大抵は /bin/sh/bin/bash だし、そうでなくても /bin/bash はデフォルトで入っています。 商用 OS も bash が入っている時代です。

#!/bin/bash で書けば大抵の仕事に対応できるね!!!1

…ただし bash もバージョン間の機能の違いは結構あります。 bash 特有の機能の利用は避け、POSIX sh 縛りで書くほうが安全です。

#!/bin/zsh で書く

ないわー。

高機能だし、 zsh のデフォルトの挙動 はスクリプトを書きやすいような気がしますが、 ポータビリティを考えるとないかなー。

自前でビルドしてインストールできる人であれば、検討の余地はあると思います。

POSIX sh 縛りのシェルスクリプトの書き方

POSIX sh 縛りのシェルスクリプトを書くのに便利な checkbashisms というコマンドがあります。引数にシェルスクリプトを指定すると、 bash 依存のコマンドや構文を指摘しまくってくれます。完璧ではありませんが、すごく便利!

Debian 系の OS であれば checkbashisms は devscripts パッケージに含まれています。 (Fedora にはないのだろうか?)

# apt-get install devscripts

checkbashisms は指定したスクリプトの shebang が #!/bin/sh でない場合は 検査を省略するため、検査を強制するために --force (-f) オプションを指定します。

例として、POSIX sh 非互換なシェルスクリプト、>突然の死<ジェネレーター echo-sdcheckbashisms にかけてみましょう。

$ checkbashisms --force ~/bin/echo-sd
possible bashism in echo-sd line 102 (alternative test command ([[ foo ]] should be [ foo ])):
if [[ ${0##*/} == echo-sd ]] && [[ ${zsh_eval_context-toplevel} == toplevel ]]; then
possible bashism in echo-sd line 102 (should be 'b = a'):
if [[ ${0##*/} == echo-sd ]] && [[ ${zsh_eval_context-toplevel} == toplevel ]]; then
possible bashism in echo-sd line 105 ($BASH_SOMETHING):
  case "${BASH_VERSION-}" in
possible bashism in echo-sd line 107 (type):
    if type zsh >/dev/null 2>&1; then
possible bashism in echo-sd line 118 (typeset):
typeset SD_arg0="$0"
possible bashism in echo-sd line 119 (typeset):
typeset SD_copyright='(C) 2013 SATOH Fumiyasu @ OSS Technology Corp., Japan'
possible bashism in echo-sd line 120 (typeset):
…省略…

bash の拡張機能は ksh 由来のものが多いため、 #!/bin/ksh なシェルスクリプトから ksh 依存度を検出するのにもある程度利用できます。

bashism?

「bashism」とは「bash]+「-ism」の造語で、「-ism」は 「主義」「理論」「慣行」「特性」などを意味します。 「POSIX sh にはない bash 特有の機能」という意味だと理解すれば正しいと思います。


ところで、12月25日はクリスマスな上に、 OSS 界隈で地味に活躍されているふみやすさんの誕生日ですね。
http://www.amazon.co.jp/registry/wishlist/27M7TV8CEEF6G?sort=priority

逆に、あなたの書いた OSS や Blog や Advent Calendar が気に入ったら何か送りたく なってしまうかもしれないので、プロフィールや Web サイトに あなたの Amazon 欲しいものリストの URL を貼っておいてくださいね!


私が勤める OSSTech っていう某弊社で社員募集しているようです。 人材紹介会社を介さなければ、入社後に 20万円のボーナス! 「ふみやすっていう人に紹介された」と言ってもらえると私にもボーナス!! → http://www.osstech.co.jp/company/recruit

バツイチでアラフォーでほとんど諦めていますが、新たなパートナーも募集中です。 ちゃんと愛情表現してくれて精神的に自立している女性がいいです。お友達から始めましょう。 → https://twitter.com/satoh_fumiyasu


よろしければ、過去の Advent Calendar もどうぞ。