環境
Ubuntu20.4
はじめに
色々なシェルスクリプトの中身を見ていると、シバンには、#!/usr/bin/bash と記述しているものもあれば、#!/usr/bin/env bash と記述しているものもあります。
はたして、どちらが正しいのでしょうか?
#!/usr/bin/bash
こちらの記述はbashの絶対パスを指定しています。確認のためにつぎのコマンドを実行すると、確かにbashの絶対パスが表示されます。
$which bash
/usr/bin/bash
シバンにこちらの記述を指定すると、シェルスクリプトを別のディストリビューションに移植したとき、ディストリビューションによってシェルが入っているディレクトリ環境が異なるため、そのままでは動かない場合が出てきます。
他の環境に移植することがない場合は、この書き方でも問題ありませんが、シェルスクリプトを一般に公開して、色々な環境でマルチに利用してもらうような場合は、このような、いち環境でしか動作しないような記述の仕方は避けるべきです。
#!/usr/bin/env bash
こちらの記述は、bashの絶対パスを指定しているのではなく、envの絶対パスを指定しています。そして、envの引数にbashを指定しています。envは実行してみると分かりますが、環境変数を一覧表示するコマンドです。こちらの記述は、汎用性が高く、bashがどこのディレクトリに入っていても、正しくbashが起動できるようになっています。
こちらの記述では、環境変数の$PATHを参照して、bashが入っているディレクトリを調べた上で、bashを正しいディレクトリから起動してくれます。つまり、bashがどこのディレクトリに入っていても、bashがちゃんと起動してくれるようになります。もちろん、PATHが切れていなければ起動できないということにはなりますが、bashのバスが切れていないといったことはまずないはずです。
bashはどこのディレクトリに入っていてもいいのですが、envだけは/usr/binに入っていないといけないことになります。しかし、この辺は心配する必要はありません。bashはディストリビューションによって、入っているディレクトリが微妙に異なる場合がありますが、envはどのディストリビューションでも、共通して同じディレクトリに入っているものです。
比較
#!/usr/bin/bashと、#!/usr/bin/env bashは、どちらも、それぞれ、長所と短所を持ち合わせています。
#!/usr/bin/bashでは、bashにオプション(引数)を渡すことができますが、#!/usr/bin/env bashにはオプションを渡すことができません。例えば、文法チェックをしたい場合、このようにオプションを指定して実行させることができます。
#!/usr/bin/bash -n
しかし、envを指定した場合は、このような使い方はできません。
#!/usr/bin/env bash -r
bashでオプションを指定して実行するようなケースは、個人的にはほぼほぼないため、あまり気にすることはないかと思います。
また、#!/usr/bin/env bashの場合は、#!/usr/bin/bashの記述よりも、セキュリティは弱いといわれています。マルウェアが仕込まれて、スクリプトが実行されることができるようになるからです。しかし、滅多に起こりうる話ではないと思われます。
結論としては、#!/usr/bin/env bashの書き方が推奨されているため、こちらで書くことにしましょうということになります。
補足
デフォルトでインストールされているシェルの一覧を表示します。
$cat /etc/shells
bashは下記の2つのディレクトリにそれぞれ入っていることがわかります。
/usr/bin/bash
/bin/bash
上記の2つのbashはどう違うのでしょうか?。結論からいうと、どちらを使っても同じということになります。
/binに入っているコマンドは、OSをシングルユーザモードで起動させても動作できるコマンドが入っており、/usr/binに入っているコマンドは、シングルユーザモードで起動させた場合は、利用できないコマンドが入っています。シングルモードで動作させる場合は、緊急のときにしか利用されません。普段利用する分には、/usr/bin/bashの方を利用しておいていいかと思います。