シェルスクリプトのシバン(Shebang)にシェル以外のコマンドを記述したらどうなるのか?
はじめに
Unix上で動作するスクリプトは、1行目に #!
から始まる1行を記述します。
これによりスクリプトの実行系を認識させることができます。
シェルスクリプトの場合は #!/bin/sh
、 #!/usr/bin/bash
、 #!/usr/bin/env bash
と記述します。
Rubyスクリプトの場合は #!/usr/bin/ruby
、 #!/usr/bin/env ruby
と記述することが多いでしょう。
この1行目の記述のことを「 シバン 」とか「 Shebang 」と呼びますが、今ひとつこのあたりの仕組が整理できてなかったため、まとめてみました。
検証環境
$ uname -moi
x86_64 MacBookPro16,1 Darwin
$ bash -version | head -n 1
GNU bash, バージョン 5.0.17(1)-release (x86_64-apple-darwin19.4.0)
(実験) #!/bin/rm
と記述し実行してみる
突然ですが、 シバン の挙動を理解するために実験をしてみます。
一行目に #!/bin/rm
とだけ記述されたシェルスクリプトを作成してみます。
# 作成
$ cat <<EOF > test.sh
#!/bin/rm
EOF
# 内容が正しいかを確認してみる
$ cat test.sh
#!/bin/rm
# 実行権限を付与
$ chmod +x test.sh
# カレントディレクトリを確認
$ ls -la
total 8
drwxr-xr-x 3 root root 96 Sep 27 13:46 .
drwxr-xr-x 1 root root 4096 Sep 27 13:34 ..
-rwx--x--x 1 root root 10 Sep 27 13:47 test.sh
作成したスクリプトを以下のように実行してみます。
$ ./test.sh
実行後、カレントディレクトリを確認してみると、 test.sh
というスクリプトがなくなっていることがわかります。
$ ls -la
total 4
drwxr-xr-x 2 root root 64 Sep 27 13:48 .
drwxr-xr-x 1 root root 4096 Sep 27 13:34 ..
これはなぜでしょう?
(実験) #!/bin/echo
と記述し実行してみる
シバン付きのスクリプトは、 スクリプト名を引数として実行される ようです。
先の実験では、 ./test.sh
を実行した結果、 /bin/rm ./test.sh
として解釈されたというわけです。
追加の実験をしてみます。
一行目に #!/bin/echo
とだけ記述されたシェルスクリプトを作成してみます。
# 作成
$ cat <<EOF > test.sh
#!/bin/echo
EOF
# 内容が正しいかを確認してみる
$ cat test.sh
#!/bin/echo
# 実行権限を付与
$ chmod +x test.sh
作成したスクリプトを、いくつかのコマンドライン引数付きで実行してみます。
$ ./test.sh aa bb ccc
./test.sh aa bb ccc
ここから、以下のようなコマンドが実行されたことがわかります。
$ /bin/echo ./test.sh aa bb ccc
改めて #!/bin/bash
の意味を考える
改めて #!/bin/bash
の意味を考えてみます。
例えば、 シバン付きの test.sh スクリプトを以下のように実行した場合を考えてみます。
$ ./test.sh aa bb ccc
これは、以下のようなコマンドが実行されることとなります。
/bin/bash ./test.sh aa bb ccc
このように整理できると、シェルスクリプトの中で ${0}
という組み込み変数が 実行されたスクリプトファイルのパス を示している仕組みが理解できるようになります。
御存知の通り、コマンドライン引数を表す変数の値は、 ${1}
は aa 、 ${2}
は bb 、 ${3}
は ccc となります。
(実験) #!/bin/echo first
と記述し実行してみる
#!/usr/bin/env bash
の意味についても考えてみたいと思います。
その前に実験です。
先程の echo
コマンドをシバンとして設定したスクリプトを多少触ってみます。
一行目に #!/bin/echo first
と記述されたシェルスクリプトを作成してみます。
$ cat <<EOF > test.sh
#!/bin/echo first
EOF
$ chmod +x test.sh
以下のように引数を付与して実行してみます。
$ ./test.sh xx yy zz
実行結果は以下の通りとなります。
first ./test.sh xx yy zz
これはつまり、 /bin/echo first ./test.sh xx yy zz
というコマンドが実行されたと解釈できます。
#!/usr/bin/env bash
も同様です。
#!/usr/bin/env bash
がシバンに設定された test.sh
スクリプトを実行すると、 /usr/bin/env bash ./test.sh
というコマンドが実行されることとなります。
補足: env
コマンドとは?
env
コマンドを通すと $PATH
環境変数の設定を使って bash
コマンドを探すため、 /bin/bash
にコマンドが配置されていない環境でも動作しますし、 bash
が複数インストールされている場合(たとえばバージョン違い)にも、最適なものを検索してくれます。
ひとこと
多少はシバンの仕組みが整理できたでしょうか?
ディスカッション
コメント一覧
まだ、コメントがありません