bash固有機能を使うときはshebangをbashにするだけでは安全とは言えない

2018/01/10

プロセス置換等、/bin/shでは利用できず/bin/bashを使う必要がある場合、シェルスクリプトを書くときに、shebangを気にする必要がある。しかし、shebangで/bin/bashを指定しても、シェルスクリプト実行時にsh script.shとしてしまうと問題が発生する。

/bin/shと/bin/bashとプロセス置換の問題

shebangが/bin/shの問題点

以下のスクリプトを例にする。

このスクリプトをshで実行すると失敗する。
実行権限がついているので、./でファイル名を書いて実行しても、shebangで#!/bin/shが指定しているので失敗する。
bashで実行すると成功する。

shebangが/bin/bashの問題点

shebangを#!/bin/bashにするといいと一般的に言われている。

bashでの実行だけでなく、./で実行できるようになる。

しかしshebangを変えても、shで実行すると失敗してしまう。

解決策

この問題を解決するために考えたのは二通りの方法。
一つはsh script.shとしてしまった場合に、誤りに気付かせること。
もう一つはプロセス置換等をする場合は必ずbashを使うように強制すること。

スクリプト起動コマンドの検知

一つ目のshebangと異なるシェルで実行していることに気付けるようにするのは可能だが、記述が若干冗長になる。
$$で自身のPIDをとれるので、ps -eの結果とPIDを照らし合わせて、スクリプトの起動コマンドを取得する。また自身の1行目を読んでshebangを見る。起動コマンドがスクリプト名と同じであれば./で実行しているので問題なく、また起動コマンドとshebangが等しくても問題ない。

全体的にbashの機能を使っていて、他人がそのスクリプトを使うときにshで起動しないように、スクリプトの冒頭に書いて制御するには使えるのではないかと思う。
しかしほとんどが/bin/shで問題ないコマンドで作成されていて、一部だけbash機能を必要とするときには、もう一つの方策であるbashの使用強制がいいと思う。

bash利用の強制

bashの利用を強制することで、/bin/bashで起動されているのか/bin/shで起動されているのかを気にしなくてもいいようにできる。
実行したいコマンドをbash -cで囲うことで、全体が/bin/shで起動されていても、問題のコマンドは/bin/bashで実行されるため、エラーが発生しない。

もしbash -cで囲うときにエスケープ等が複雑になる場合は、ヒアドキュメントを使用して実行したいコマンドを出力させ、標準入力をbashが読み込むようにするといい。

以下のようにエスケープが複雑な場合は簡単に書ける。他にはawkを使う場合もエスケープが面倒になりがちなので、ヒアドキュメントを使うといいだろう。

-Linux
-