今回の動作確認環境
- Vagrant 2.2.14
- CentOS 8
- bash 4.4.19
shebangで指定可能な形式について
shebangとは実行可能権限が付与されたシェルスクリプトの先頭行に書かれている #!/bin/sh
の部分のことを指します。
シェルスクリプトでよく見かける形式としては、以下のようなものではないでしょうか。
#!/bin/sh
#!/usr/bin/bash
スクリプト言語を利用する方であれば、こういった形式で書かれているかと思います。
#!/usr/bin/perl
#!/usr/local/bin/ruby
#!/usr/bin/env python3
/usr/bin/perl
や /usr/bin/env
からわかるように、 /etc/shells
に記載されているようなシェルのパス以外の実行ファイルでも指定できることに気づきます。
Wikipediaによると shebang
として指定可能なのは「the file specified by interpreter must be an executable binary and cannot itself be a script.」とのこと。
つまり、実行可能なバイナリファイルで、shebangを書いてるシェルスクリプト自身以外であればOKみたいです。
Wikipedia内にexecveのマニュアルページへの参照リンクが貼られていたので man execve
を見てみると以下のように DESCRIPTION
に記述されていました。
DESCRIPTION
execve() executes the program pointed to by filename. filename must be either a
binary executable, or a script starting with a line of the form:
#! interpreter [optional-arg]
shebang
に指定できるのは、以下のいずれかのようです。
- 実行可能なバイナリ
- 「#!」で始まるシェルスクリプト
「1」については「/usr/bin/bash」、「/usr/bin/perl」、「/usr/bin/env」といった記述から理解できます。
「2」については、ちょっと試してみましょう。
vagrantユーザのホームディレクトリ直下に like_echo.sh
という第1引数をechoするシェルスクリプトを準備して、実行権限を付与します。
$ pwd
/home/vagrant
$ cat like_echo.sh
#!/bin/bash
echo $1
$ chmod +x like_echo.sh
like_echo.sh
に arg1
を渡して呼び出す call_like_echo.sh
を準備して、これにも実行権限を付与します。
$ cat call_like_echo.sh
#!/home/vagrant/like_echo.sh arg1
$ chmod +x call_like_echo.sh
実行してみると arg1
が出力されました。これで「or a script starting with a line of the form:〜」の部分の検証ができたかと思います。
$ ./call_like_echo.sh
arg1
ちなみ call_like_echo.sh
でshebang
行で渡す引数の数を増やすとこんな動きになります。
引数を2つ渡して実行。
$ cat call_like_echo.sh
#!/home/vagrant/like_echo.sh arg1 arg2
$ ./call_like_echo.sh
arg1 arg2
引数を3つ渡して実行。
$ cat call_like_echo.sh
#!/home/vagrant/like_echo.sh arg1 arg2 arg3
$ ./call_like_echo.sh
arg1 arg2 arg3
この動きから like_echo.sh
で受け取った $1
には call_like_echo.sh
の shebang
行で指定した「arg1 arg2 arg3」の部分すべてが第1引数として扱われているようです。
echoで実行状況を可視化
ここまでで shebang
には /bin/sh
のようなシェル以外でも man execve
に記載されている条件を満たしていれば指定できることがわかりました。
また、さきほどの like_echo.sh
の動作から、 shebang
で #!/bin/bash
と指定すると、以下のような呼び出され方をしていることがわかります。
$ /bin/bash like_echo.sh 引数
当然と言えば当然の動きなんですが。。。この動きを echo
コマンドを使って可視化してみましょう。
shebang
に echo
コマンドのパスを記述して、実行権限を付与します。
$ cat echo.sh
#!/usr/bin/echo
$ chmod +x echo.sh
実行すると、シェルスクリプト自体のファイル名が出力されました。
$ ./echo.sh
./echo.sh
ということは shebang
行に #!/usr/bin/echo
と指定することで、実際にはこのように呼び出されたことがわかります。
$ /usr/bin/echo ./echo.sh
引数を渡してみると /usr/bin/echo ./echo.sh 引数
のように呼び出されていることが可視化できていますね。
引数が1つの場合。
$ ./echo.sh arg1
./echo.sh arg1
引数が2つの場合。
$ ./echo.sh arg1 arg2
./echo.sh arg1 arg2
wcで行数を数えてみる
shebangで指定したコマンド ./自身のファイル名 引数
の形式でシェルスクリプトが実行されることがわかったので、この仕組みを使ってファイルの行数を数えてみます。
こんなファイルを準備して、実行権限を付与します。
$ cat wc.sh
#!/usr/bin/wc -l
# Comment1
# Comment2
# Comment3
# Comment4
# Comment5
$ chmod +x wc.sh
実行するとファイルの行数が出力されました。
$ ./wc.sh
6 ./wc.sh
cpでシェルスクリプトのコピーを作成する
こうなってくると、自身のファイル名を使った操作が色々と可能ですね。
ファイルのコピーを行うスクリプトを準備して、実行権限を付与します。
$ cat cp.sh
#!/usr/bin/cp
$ chmod +x cp.sh
引数に cp.sh.YYYYMMDDHHMMSS
形式のファイル名を渡すと cp.sh
がコピーされて cp.sh.20210711042853
が作成されました。
$ ./cp.sh cp.sh.`date '+%Y%m%d%H%M%S'`
$ ls -l cp.sh.20210711042853
-rwxrwxr-x. 1 vagrant vagrant 14 Jul 11 04:28 cp.sh.20210711042853
まとめ
-
shebang
は「実行可能なバイナリ」もしくは「#!
で始まるシェルスクリプト」が指定できる。 -
shebang
に#!/PATH/TO/コマンド コマンドの引数
と記述して./シェルスクリプト名 シェルスクリプトの引数
のように実行すると、実際には/PATH/TO/コマンド コマンドの引数 ./シェルスクリプト名 シェルスクリプトの引数
のような形式で実行されている。
参考URL
- シバン(shebang)にスクリプトを実行しないコマンドを指定してみる実験
- シェルスクリプトのシバン(Shebang)にシェル以外のコマンドを記述したらどうなるのか?
- 作業の自動化、謎のおまじない shebang(シバン)、PATH を設定する
- What is shebang (#!/bin/sh) in POSIX shell script
- シェルのshebang が実行されるときの引数を見てみる。
- shebangから理解するUNIXの仕組み
- /bin/shと/bin/bashの違い(とcronでのシェル)
- スクリプト言語 C —— shebangのないテキストファイルはいかに実行されるか
- PythonスクリプトからShebangの意味を考えてみる
- Perl, Python 及び Ruby スクリプトにおける正しいshebangの書き方
- シェルスクリプトの冒頭でbashを明示する(提案)
- #!/bin/sh は ただのコメントじゃないよ! Shebangだよ!
- bash スクリプトの先頭によく書く記述のおさらい
- 手を動かして理解するshebang
- シバン (shebang) を書いた方が可搬性が高いシェルスクリプトになる
- shebang