LinuxやmacOSでシェルスクリプトを書くとき、最初に悩むのが「#!/bin/bash と #!/bin/sh のどちらを使えばよいか」という問題です。
この記事では、BashとShの違いを構文・機能・ポータビリティの観点で整理し、どちらを使うべきかを判断できるよう解説します。
shとは?bashとは?
sh(Bourne Shell)
sh(Bourne Shell)は1977年に開発されたUnixの標準シェルです。POSIX標準に準拠しており、LinuxやBSD、macOSなど多くのUNIX互換OSで動作します。現代の多くのLinuxディストリビューションでは /bin/sh は dash(Debian Almquist Shell)や bash へのシンボリックリンクになっています。
bash(Bourne Again Shell)
bash(Bourne Again Shell)は1989年にGNUプロジェクトが開発したshの後継シェルです。shのすべての機能を備えつつ、配列・コマンド履歴・タブ補完・拡張文字列操作など多くの機能が追加されています。Linuxのデフォルトシェルとして広く使われており、macOSではバージョン10.15 Catalina以前はデフォルトでした(現在はzsh)。
shebang(シバン)行の違い
スクリプトの1行目に書く shebang によって、どのシェルで実行するかが決まります。
#!/bin/sh # sh(またはdash)で実行
#!/bin/bash # bash で実行
#!/usr/bin/env bash # PATH上のbashで実行(推奨)
#!/bin/sh:POSIX準拠のshで実行。bash特有の構文は使えない#!/bin/bash:bashで実行。bash特有の機能が使える#!/usr/bin/env bash:PATH上のbashを探して実行。異なる環境に対応しやすい
Ubuntuでは /bin/sh は dash(bashより高速だが機能が少ない)へのシンボリックリンクです。そのため、#!/bin/sh で書いたスクリプトにbash専用構文が混入すると、Ubuntuで実行エラーになります。
# Ubuntuでの確認方法
ls -la /bin/sh
# /bin/sh -> dash
# macOSでの確認
ls -la /bin/sh
# /bin/sh -> /private/var/select/sh
sh と bash の構文の違い
以下の表で、sh(POSIX)とbash専用の構文を比較します。
| 機能 | sh(POSIX) | bash専用 |
|---|---|---|
| 配列 | 非対応 | arr=(a b c); echo ${arr[0]} |
| 連想配列 | 非対応 | declare -A map; map[key]=val |
| 文字列長 | ${#var} |
同じ(共通) |
| 部分文字列 | ${var#prefix} |
${var:2:5}(拡張) |
| 正規表現マッチ | 非対応 | [[ $s =~ ^[0-9]+$ ]] |
| プロセス置換 | 非対応 | diff <(cmd1) <(cmd2) |
| here-string | 非対応 | cmd <<< "string" |
| 算術式 | $(( expr )) |
同じ(共通) |
| ローカル変数 | local(一部対応) |
local var=val |
| コマンド履歴 | なし | あり |
| タブ補完 | なし | あり |
| [[ ]] テスト | 非対応 | [[ ... ]](拡張テスト) |
具体的な構文の違い:コード例
配列(bash のみ)
#!/bin/bash
# bash でのみ動作
fruits=("apple" "banana" "cherry")
echo "${fruits[0]}" # apple
echo "${#fruits[@]}" # 3(配列の長さ)
for f in "${fruits[@]}"; do
echo "$f"
done
#!/bin/sh
# sh では配列を使えないので、スペース区切りの文字列で代替
fruits="apple banana cherry"
for f in $fruits; do
echo "$f"
done
文字列操作(bash の拡張)
#!/bin/bash
filename="report_2024.txt"
# bash 専用:位置と長さで部分文字列を抽出
echo "${filename:7:4}" # 2024
# bash 専用:大文字・小文字変換
echo "${filename^^}" # REPORT_2024.TXT
echo "${filename,,}" # report_2024.txt
条件テスト(bash の [[ ]] 拡張)
#!/bin/bash
# bash 専用:[[ ]] は正規表現マッチや && || が使える
str="hello123"
if [[ $str =~ ^[a-z]+[0-9]+$ ]]; then
echo "マッチした"
fi
# sh 共通:[ ] は POSIX 互換
if [ -f "/etc/passwd" ] && [ -r "/etc/passwd" ]; then
echo "ファイルが存在して読み取れる"
fi
プロセス置換(bash のみ)
#!/bin/bash
# 2つのコマンドの出力を直接diff(bash専用)
diff <(ls dir1/) <(ls dir2/)
# sh では一時ファイルを使う必要がある
ls dir1/ > /tmp/list1.txt
ls dir2/ > /tmp/list2.txt
diff /tmp/list1.txt /tmp/list2.txt
rm /tmp/list1.txt /tmp/list2.txt
パフォーマンスとポータビリティ
| 観点 | sh(dash) | bash |
|---|---|---|
| 起動速度 | 速い(軽量) | やや遅い |
| 機能 | POSIX基本機能のみ | 豊富な拡張機能 |
| ポータビリティ | 高い(あらゆるUNIXで動く) | やや低い(bash未インストール環境もある) |
| インタラクティブ使用 | 限定的 | 履歴・補完など快適 |
組み込みシステムやDockerコンテナの Alpine Linux では bash がデフォルトでインストールされていないことがあります。そのような環境向けスクリプトは #!/bin/sh で書く方が安全です。
どちらを使うべきか:判断基準
sh(POSIX)を選ぶケース
- 複数のUNIX/Linux環境で動作させる必要がある
- Alpine LinuxなどbashがないDockerコンテナで動かす
- 組み込みシステムやシンプルな初期化スクリプト
- システム起動スクリプト(
/etc/init.d/など)
bash を選ぶケース
- 配列や連想配列を使いたい
- 正規表現マッチ(
[[ =~ ]])を使いたい - プロセス置換(
<())を使いたい - 開発用の自動化スクリプト(特定の環境に限定されている)
- インタラクティブな操作(コマンドライン使用)
迷ったときのルール
スクリプトが実行される環境が明確にLinuxサーバーだけで、配列などの機能を使いたいなら bash を選びましょう。一方で「どこでも動く」ことが重要なら sh(POSIX) に徹するのが安全です。
よくある質問
Q. Ubuntuでshスクリプトをbashとして動かしてしまっています
Ubuntuで /bin/sh は dash です。もし #!/bin/sh のスクリプトにbash構文(配列など)を書くと、dashでの実行時にエラーになります。bash専用機能を使う場合は必ず #!/bin/bash を使いましょう。
Q. スクリプトを実行するとき、shebangとは別にbashを指定できますか?
はい、できます。コマンドラインで明示的にインタープリタを指定すると、shebangの指定より優先されます。
bash script.sh # shebangに関わらずbashで実行
sh script.sh # shebangに関わらずshで実行
Q. macOSではbashとshのどちらが使えますか?
macOS Catalina(10.15)以降、デフォルトシェルは zsh に変わりました。ただし bash(バージョン3.2)と sh(dashへのリンク)はいずれも利用可能です。bash 5.x を使いたい場合は brew install bash でインストールできます。
Q. shスクリプトをbashに対応させるにはどうすればよいですか?
shebangを #!/bin/sh から #!/bin/bash(または #!/usr/bin/env bash)に変更するだけです。shはbashの機能のサブセットなので、POSIX準拠のshスクリプトはbashでも動きます。
Q. shellcheck とは何ですか?
ShellCheck はシェルスクリプトの構文チェックツールです。sh向けスクリプトにbash専用の構文が混入していないかなどを検出できます。スクリプトを書く際に活用すると品質が上がります。
関連コマンド・記事
- Bash スクリプト入門:bashの基本的な書き方
dash:Ubuntuのデフォルトsh実装zsh:macOSのデフォルトシェル(bashの上位互換的な存在)

コメント