sh コマンドとは?bashとの違いと使い分け:初心者向けガイドとスクリプト例

環境&ワークフロー

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/shdash(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/shdash(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/shdash です。もし #!/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の上位互換的な存在)
Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント