シバン(shebang)にスクリプトを実行しないコマンドを指定してみる実験


シェルスクリプトを書く時、おまじないのように先頭行を #!/bin/bash などとしていた。( #! はシバンなどと呼ばれる)

色々なスクリプトを見ていたら、シェルを宣言しているわけではなく自身のスクリプトを実行するコマンドを書けばいいらしいとわかった。

  • awk#!/usr/bin/awk -f
  • expect#!/usr/bin/expect -f
  • perl → #!/usr/bin/perl
    • PATHに従う場合 → #!/usr/bin/env perl参考

だったらスクリプトを実行しないコマンドを書いてもそれに応じた動作をするのでは、と思って試してみた。実用性は無いと思う。

実験

単独で実行するときは権限が必要なので、事前に chmod u+x script-* などとパーミッションを適切に設定しておくこと。

echo

簡単で無害そうなコマンドから試す。 echo は引数を表示するコマンド。

script-echo
#!/bin/echo
echo "Hello, world!"
$ bash script-echo  # 普通にシェルスクリプトとして実行 → 普通の結果
Hello, world!

$ ./script-echo
./script-echo

$ ./script-echo arg1 arg2
./script-echo arg1 arg2

どうやら /bin/echo ./script-echo arg1 arg2 と実行した感じになるらしい。引数にファイル名が来ても問題ないコマンドなら大丈夫そう。

cat

引数にファイル名をとるコマンドの代表、 cat もやってみる。

script-cat
#!/bin/cat
echo "Hello, world!"
$ ./script-cat 
#!/bin/cat
echo "Hello, world!"

書いたスクリプトは実行されず、自身のファイルの中身が表示された。

false

false は何もせず失敗するコマンド(引数や入力も無視する1)。なのでシバンに書いておくと、直接実行するのを禁止することになる。

シェルの組み込みコマンドになっていたり、OSによってパスが違っていたりする。ファイルは whereis false とすれば探せる。

script-false
#!/bin/false
echo "Hello, world!"
$ ./script-false

$ echo $?  # コマンドの終了ステータスを確認
1

rm

自爆。ファイルが消滅する。

何も表示されないのは面白くないので -i を付けておく。

script-rm
#!/bin/rm -i
echo "Goodbye, world!"
$ ./script-rm
/bin/rm: remove regular file './script-rm'? y

$ ls -l script-rm
ls: cannot access 'script-rm': No such file or directory

追加の実験

上で試したコマンドはファイルの内容に依らないものだった。そのため内容は大して意味のないものになってしまった。

ファイルの内容に意味があり、シバンを加えても邪魔にならないものを考えたところ、# をコメント扱いするアプリのファイル」なら良いはずと思った。そのようなものは各種スクリプトだけでなく一部の設定ファイルも当てはまる。

というわけで実行可能な設定ファイルを作れるか簡単に試してみる。

sshd

SSHサーバーは起動時に -f オプションで設定ファイルを指定できる。なお、設定項目は以下を参考にした。

sshd-custom
#!/usr/sbin/sshd -f
# ↑これが今回の実験テーマ

# わかりやすく、通常と異なるポートを指定
Port 2222

# 安全のためループバックインターフェースのみ使用
ListenAddress 127.0.0.1

# 実験目的ということでパスワード認証
PasswordAuthentication yes
PermitEmptyPasswords yes
PubkeyAuthentication no  # "Too many authentication failures" 対策

あとはこのファイルを実行してみるだけ。するときちんとSSHサーバーが起動する。

$ chmod +x sshd-custom
$ sudo ./sshd-custom  # サーバー起動(サーバー鍵を読む都合上root権限が必要)

$ ssh -p 2222 localhost  # ポートを指定して接続
<パスワードを入力する>
<ログインできたら適当に遊ぶ>

$ sudo pkill sshd-custom  # サーバー停止

  1. --help などのオプションを受け付ける実装もある。例:GNU Coreutils