Bash vs Dash:シェルスクリプト書くならどっち?比較と選び方
Webサイトの運用や開発をしていると、ちょっとした定型作業を自動化したくなりますよね。そんな時に大活躍するのが「シェルスクリプト」です。でも、いざ書き始めると、ファイルの1行目に書かれている #!/bin/bash や #!/bin/sh といったおまじないのような記述に「これって何が違うの?」と疑問に思ったことはありませんか?
実はこの違い、とっても重要なんです。特に「自分のパソコンでは完璧に動いたのに、サーバーに持っていったらエラーが出た!」なんて悲劇を避けるためには必須の知識です。この記事では、よく使われる2つのシェル、BashとDashの違いを、初心者の方にも分かりやすく、コピペで試せるコードを交えながら徹底解説します。この記事を読めば、あなたも環境に左右されない堅牢なシェルスクリプトが書けるようになりますよ!
BashとDash、そもそも何者?
まずは、主役の2人(2つのシェル)について紹介します。それぞれの得意なことや性格を知るのが、仲良くなるための第一歩です。
Bash (Bourne-Again SHell) - みんなの相棒、多機能シェル
Bashは、多くのLinuxシステムやmacOS(古いバージョン)で、私たちがターミナルを開いたときに最初に起動する「ログインシェル」として採用されています。コマンドの履歴を矢印キーで遡ったり、Tabキーでコマンドやファイル名を補完したり、カラフルな表示を使ったり… 私たちが普段、意識せずに使っている便利な機能の多くはBashが提供してくれています。人間が直接操作(インタラクティブな利用)するのに非常に向いている、高機能でフレンドリーなシェルと言えるでしょう。
Dash (Debian Almquist SHell) - 縁の下の力持ち、高速・軽量シェル
一方のDashは、とにかく軽量で高速なのが特徴です。余計な機能が削ぎ落とされている分、スクリプトをサッと実行するのに特化しています。この特徴から、特にUbuntuなどのDebian系のOSでは、システムの起動スクリプトや、#!/bin/sh で指定されたときのデフォルトシェルとして採用されています。つまり、私たちが直接触る機会は少なくても、システムの裏側ではDashがバリバリ働いている、というわけです。
最大の分かれ道:「方言」と「標準語」としてのPOSIX準拠
BashとDashの最大の違いは、POSIX(ポジックス)という規格にどれだけ忠実か、という点にあります。
いきなり専門用語が出てきて戸惑ったかもしれませんね。簡単に言うと、POSIXは「シェルスクリプト界の標準語」のようなものです。この標準語で書かれたスクリプトは、どんな環境(OS)でも同じように動くことが保証されています。
- Dash: POSIXという「標準語」にとても忠実。方言はほとんど話せません。
- Bash: 「標準語」も話せるけど、便利な「方言」(Bash独自の拡張機能)をたくさん知っている。
私たちが普段ターミナルで使っている便利な機能は、Bashの「方言」であることが多いのです。そして、多くのシステムで /bin/sh は「標準語しか通じないシェル(Dashなど)」を指しています。これが「自分のPC(Bash)では動くのに、サーバー(/bin/sh)では動かない」現象の主な原因です。
スクリプトの1行目に #!/bin/bash と書けば、「このスクリプトはBashの方言を使いますよ!」と宣言することになり、Bashの便利機能が使えます。逆に #!/bin/sh と書くことは、「標準語でお願いします!」と宣言するようなもの。移植性や互換性を高めたいなら、#!/bin/sh を使い、POSIX準拠の書き方を意識するのがセオリーです。
【実践】コードで比較!BashとDashで書き方はどう違う?
ここからは、具体的なコードを見ながら、Bashの「方言」と、Dashでも動くPOSIX準拠の「標準語」の書き方を比較していきましょう。「動く」を体験するために、ぜひコピーしてあなたのターミナルで実行してみてください!
1. 配列の扱い
複数の値をまとめて扱いたいときに使う配列。Bashでは直感的に書けますが、POSIX標準には配列の仕様がありません。そのため、Dashで同じことをするには少し工夫が必要です。
Bashの書き方(方言)
() を使って簡単に配列を定義し、${my_array[1]} のようにインデックスを指定して要素を取り出せます。
#!/bin/bash
# 配列を定義
fruits=("apple" "banana" "cherry")
# 2番目の要素(インデックスは0から始まる)を出力
echo ${fruits[1]}
実行結果:
banana
Dashでも動く書き方(標準語)
POSIX準拠で書く場合、配列の代わりにスペース区切りの文字列や、シェルの位置パラメーター($1, $2...)を利用します。ここでは位置パラメーターを使う方法を紹介します。set -- で各単語を位置パラメーターにセットし、forループで順番に処理するのが定石です。
#!/bin/sh
# スペース区切りの文字列として定義
fruits="apple banana cherry"
# forループですべての要素を順番に出力
for fruit in $fruits; do
echo "I like $fruit!"
done
実行結果:
I like apple!
I like banana!
I like cherry!
2. 条件分岐の書き方
「もし○○なら△△する」という条件分岐はスクリプトの基本です。ここにも大きな違いがあります。
Bashの書き方(方言)
Bashでは [[ ... ]] という、より高機能なテストコマンドが使えます。&& を使って複数の条件を繋げたり、== での文字列比較やパターンマッチングができたりと非常に便利です。
#!/bin/bash
name="Taro"
age=25
# 2つの条件を&&で繋ぐ
if [[ "$name" == "Taro" && "$age" -gt 20 ]]; then
echo "Welcome, Taro!"
fi
実行結果:
Welcome, Taro!
Dashでも動く書き方(標準語)
POSIX準拠のテストコマンドは [ ... ] です。こちらは古くからあるコマンドで、いくつかの制約があります。例えば、文字列比較は = (イコール1つ)を使い、複数の条件は -a (AND) や -o (OR) を使うか、[ ] を複数組み合わせる必要があります。安全のため、[ ] を複数組み合わせるのがおすすめです。
#!/bin/sh
name="Taro"
age=25
# [ ] を2つ使って条件を記述する
if [ "$name" = "Taro" ] && [ "$age" -gt 20 ]; then
echo "Welcome, Taro!"
fi
実行結果 (同じ):
Welcome, Taro!
3. 文字列の置換
変数の中の特定の文字を別の文字に置き換えたい、というケースもよくあります。
Bashの書き方(方言)
Bashでは、${変数/置換前/置換後} という書き方で簡単に文字列を置換できます。
#!/bin/bash
filename="photo_2025.jpg"
# "jpg" を "png" に置換
new_filename=${filename/jpg/png}
echo $new_filename
実行結果:
photo_2025.png
Dashでも動く書き方(標準語)
POSIX準拠で書く場合、文字列操作は sed や awk といった外部コマンドを組み合わせるのが一般的です。ここでは sed を使った例を紹介します。少し長くなりますが、どんな環境でも確実に動くという安心感があります。
#!/bin/sh
filename="photo_2025.jpg"
# echoで変数の中身をsedコマンドに渡し、置換処理を行う
new_filename=$(echo "$filename" | sed 's/jpg/png/')
echo "$new_filename"
実行結果 (同じ):
photo_2025.png
結論:結局、どっちを使えばいいの?
ここまで違いを見てきましたが、「じゃあ、どっちを使えばいいの?」というのが一番知りたいことですよね。答えは「時と場合による」ですが、初心者の方におすすめの指針はあります。
ユースケース別・おすすめの選び方
-
ターミナルで手軽に作業したいとき 👉 迷わずBash!
普段使いのシェルでは、補完や履歴などの便利な機能をフル活用しましょう。わざわざ不便な書き方をする必要はありません。 -
サーバーで動かすスクリプトや、他人に配布するスクリプトを書きたいとき 👉 Dash(POSIX準拠)を強く意識!
あなたの環境だけで動けば良い、というものでなければ、互換性が最も重要になります。#!/bin/shを使い、POSIXの「標準語」で書くことを心がけましょう。これにより、スクリプトがLinuxでもBSDでも、将来登場する新しいシステムでも、動き続ける可能性がぐっと高まります。
初心者へのアドバイス
もしあなたがシェルスクリプトを学び始めたばかりなら、最初から #!/bin/sh で、POSIX準拠の書き方を学ぶことをおすすめします。なぜなら、「大は小を兼ねる」からです。POSIX準拠で書かれたスクリプトはBashでも問題なく動きますが、その逆は成り立ちません。最初に「標準語」をマスターしておけば、どんな環境に行っても困ることがないのです。
気をつけて!うっかり使いがちなBashの「方言」(Bashism)
良かれと思って書いたコードが、実はBashの「方言」だった… というのはよくある話です。ここでは特にやりがちな「Bashism(バシズム)」をいくつか紹介します。
[[ ... ]]: 先ほども出ましたが、最も代表的なBashismです。条件分岐は[ ... ]で書く癖をつけましょう。function my_func { ... }: 関数を定義するときのfunctionキーワードはBashのものです。POSIX準拠ではmy_func() { ... }と書きます。echo -e "...":\n(改行)などのエスケープシーケンスを解釈してくれる-eオプションですが、これも全てのシェルで共通の挙動をするわけではありません。代わりにprintfコマンドを使うのがはるかに安全で確実です。source ./my_script.sh: 別のスクリプトを読み込むsourceコマンドもBashismです。POSIX準拠では. ./my_script.sh(ドットとスペース)を使います。
これらのBashismを避けるだけで、あなたのスクリプトの互換性は劇的に向上します。
まとめ:Bashの便利さとDashの堅牢性を使いこなそう!
今回は、BashとDashの違いを通じて、互換性の高いシェルスクリプトの書き方について解説しました。
- 普段ターミナルで使うのは、便利な機能が満載のBash。
- スクリプトを書くときは、どんな環境でも動くようにDash (POSIX準拠) を意識する。
- 迷ったら、スクリプトの1行目には
#!/bin/shを書き、POSIXの「標準語」で書く練習をするのがベストプラクティス。
この考え方を身につければ、「環境のせいで動かない」というトラブルを未然に防ぎ、より多くの場面で役立つスクリプトを書けるようになります。さあ、あなたも今日から「どこでも動くシェルスクリプト」を目指してみませんか?