#!/bin/sh は Ubuntu と Redhat(RHEL)互換OSで実体が異なるのでシェルスクリプトで注意

ALL
スポンサーリンク
スポンサーリンク

はじめに

/bin/sh は、Ubuntu と Redhat(RHEL)互換OS(CentOS,RockyLinux,AlmaLinux)ではシンボリックリンクであり、そのリンク先が次のように異なるシェルになっています。そのため、sh で実行されるシェルスクリプトは、Ubuntu と Redhat(RHEL)互換OSで挙動が異なることがあるので注意が必要です。

Ubuntu
/bin/sh -> dash

Redhat(RHEL)互換OS(CentOS,RockyLinux,AlmaLinux)
/bin/sh -> bash

bash と dash の違い

sh がリンクされている dash(Ubuntuの場合)と、bash(Redhat(RHEL)互換OSの場合)で、異なる点をいくつかあげます。

echo のエスケープシーケンス

\n といったエスケープシーケンスは、dashはデフォルトで解釈しますが、bashは -eオプションをつけた時のみ解釈します。

dash(Ubuntuの場合)
$ dash -c "echo 'a\nb'"
a
b

# dash で -e をつけると、それが出力されてしまう
$ dash -c "echo -e 'a\nb'"
-e a
b

bash(Redhat(RHEL)互換OSの場合)
$ bash -c "echo 'a\nb'"
a\nb

# -e をつけると、エスケープシーケンス処理して dash と同じになる
$ bash -c "echo -e 'a\nb'"
a
b

printf を使うと、両者ともエスケープシーケンス処理します。

dash(Ubuntuの場合)
$ dash -c "printf 'a\nb'"
a
b

bash(Redhat(RHEL)互換OSの場合)
$ bash -c "printf 'a\nb'"
a
b

関数定義時の function

関数定義では、dash では function の記述はサポートされませんが、bashではfunction の記述あり/なし両方サポートします。

dash(Ubuntuの場合)

# NG
function test(){
    echo TEST
}

# OK
test(){
    echo TEST
}

bash(Redhat(RHEL)互換OSの場合)

# OK
function test(){
    echo TEST
}

# OK
test(){
    echo TEST
}

シェルスクリプト実行

dash では . で読み込み実行します。カレントディレクトリのスクリプトでは ./スクリプト名 のように ./ が必要です。
bash では source , . 両方で読み込み実行します。カレントディレクトリのスクリプトでは ./ は不要です。

dash(Ubuntuの場合)

# OK
$ dash -c ". ./test.sh"

# NG
$ dash -c ". test.sh"

# NG
$ dash -c "source ./test.sh"

# NG
$ dash -c "source test.sh"
NG

bash(Redhat(RHEL)互換OSの場合)

# OK
$ bash -c ". ./test.sh"

# OK
$ bash -c ". test.sh"

# OK
$ bash -c "source ./test.sh"

# OK
$ bash -c "source test.sh"

その他

2008年とちょっと古いですが、bash と dash の違いが説明されています。

https://princessleia.com/plug/2008-JP_bash_vs_dash.pdf

参考

にわか管理者のためのLinux運用入門(317) Macで行く – bashとdashの違いを知る | TECH+(テックプラス)
bash – BashとDashでechoのエスケープシーケンスに対する挙動が異なるのは何故? – スタック・オーバーフロー
https://princessleia.com/plug/2008-JP_bash_vs_dash.pdf

コメント