Bashのシェルスクリプトのshebang行は #!/usr/bin/env bash の方がいいかもしれない

シェルスクリプトを記載する時、bashで実行されることを意識する際、冒頭のシェバン (shebang) 行に

1
#!/bin/bash

と記載することが多いです。

Linuxではこれで全く問題ないのですが、近年の macOS の状況を見ていると、これはちょっと考え直した方がいいかなと思ってきました。

簡潔に言うと、

1
#!/usr/bin/env bash

とするのが汎用性の高い運用になると思います。

以降、丁寧な説明です。

シェバン行とは、Unixライクなシステムでスクリプトファイルの1行目に書く特別な行で、通常 “#!” で始まります。この行は、そのスクリプトを実行するためのインタープリタのパスを指定します。

冒頭に記載した

1
#!/bin/bash

は、このスクリプトは /bin/bash を使いなさいと指示しているわけです。

で、macOS でこれのバージョンを見てみます。

1
2
3
/bin/bash --version
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin23)
Copyright (C) 2007 Free Software Foundation, Inc.

とバージョン 3.2.57 であることがわかります。macOSはライセンスの問題で bash のバージョンを 3 よりはあげないことにしていると聞いています。(bash のライセンスはバージョン3までは GPL v2, バージョン4以降は GPL v3 です)

Linuxで現在使われているバージョンを確認してみます。たとえばUbuntu 22.04では

1
2
3
4
5
6
7
/bin/bash --version
GNU bash, バージョン 5.1.16(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>
 
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

とバージョン5.1.16であることがわかります。

なので、もしスクリプトでバージョン4以降でしか有効でない機能をいれたら、macOSでは不具合が出ます。
実際に最近、そのような経験をしました。連想配列を使ったスクリプトを配布したところ、macOSのデフォルトの bash では実行されずにトラブルが続出しました。

連想配列とは以下のようなものです。

1
2
3
4
declare -A colors
colors[red]="#FF0000"
colors[green]="#00FF00"
colors[blue]="#0000FF"

このように連想配列 colors を定義すると

1
echo "${colors[red]}"

とすると、#FF0000 が出力されます。

このような機能が使えないわけです。

一方、macOSでは、 Homebrew で bash の最新版を入れることができます。

その場合、パスを指定せずに bash –version を実行すると以下のようになります。

1
2
3
4
5
6
7
bash --version
GNU bash, バージョン 5.2.37(1)-release (aarch64-apple-darwin23.4.0)
Copyright (C) 2022 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>
 
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

ちなみに

1
which bash

をすると、

1
/opt/homebrew/bin/bash

となります。(HomebrewはIntel macでは/usr/local/homebrewに、Apple Siliconは /opt/homebrew に入るようです)

で、パスが /opt/homebrew/bin/ に通っていますので、bash をインタラクティブシェルで実行すると、homebrewのbashが実行されます。

ただ、上記のように macOS はCPUの違いで bash のパスが異なります。より汎用性のある方法はないでしょうか。

そこで出てくるのが env となります。

env コマンドは環境変数 PATH を参照して、指定されたコマンドを探してくれます。そのため、シェバン行を

1
#!/usr/bin/env bash

とすることで、以下のような利点が得られます:

  • システムの PATH環境変数 に基づいて最適な bash を自動的に選択してくれます
  • Intel MacでもApple SiliconのMacでも、Homebrewでインストールしたより新しいバージョンのbashを優先的に使用できます
  • システムによってインタープリタの場所が異なる場合でも、柔軟に対応できます

この方法は、bashに限らず他のスクリプト言語でも広く使われている手法です。例えば以下のような感じです。

1
2
3
#!/usr/bin/env python3
#!/usr/bin/env node
#!/usr/bin/env ruby

このように、envを使用したシェバン行は、異なるプラットフォームやシステム構成での互換性を確保する上で、より汎用的になると感じました。特に、異なるOS環境で作業する可能性が高い場合や、スクリプトを広く配布する場合は、この方法が適切だなと思いました。

以上をまとめると、今後、bashを使ったシェルスクリプトのシェバン行は

1
#!/usr/bin/env bash

でいきたいと思いました。

最後に、一括で書き換えられるスクリプトを書きました。こちらのリンクからダウンロードできます(右クリックで名前をつけて保存)。

1
./update-shebang.sh check <ディレクトリ>

で、 #!/bin/bash で始まるスクリプトを探し、

1
./update-shebang.sh update <ディレクトリ>

で #!/usr/bin/env bash に置き換えます。

コメントを残す

This site uses Akismet to reduce spam. Learn how your comment data is processed.