街中で見かけて「グッときた人」の思い出

bashのスクリプトの一行目に、環境に合わせて、
#!/bin/gawk -f
とか
#!/usr/local/bin/bash -f
とか書かないとだめですよね。

環境が変わるごとに(bashのパスが変わるごとに)この部分を書き換えるのが面倒なのですが、よい方法はないものでしょうか?

A 回答 (5件)

#!の次の文字列をプログラムと見なして、残りの文字列をそのプログラムへの第一引数として、ファイル名を第二引数としてプログラムを実行するというのはbash等のシェルの機能じゃなくてOSカーネルの機能です。

カーネルの機能のため、シェルのような複雑なコマンドライン解析機能は組み込まれていません。

一行目が#!で始まらない実行可能ファイルをシェルから起動した場合、シェルスクリプトとして実行されるのでbashからbashスクリプトを実行するなら1行目からいきなりスクリプトを書けばOKです。ただしシェル以外から起動される場合はエラーになりますが。直接シェルから起動しなくても例えばC言語のsystem()関数はシェル経由でプログラムを起動するのでこういった場合もOKです。

>・env がスペース付き引数に対応する
env は元々、env VAR=value cmd arg1 arg2 のようにcmd arg1 arg2 を実行する際に環境変数VARにvalueという値を設定してから実行するというコマンドなのでこういう変更はありえないです。envの改造じゃなくてコマンドラインを解析するミニシェルを作ってそれを
#!/bin/minish awk -f のように指定すればOKです。

>・"gawk -f" に対応するコマンド gawkf (?)を用意する(gawk -f を一つの引数にするため)
そのgawkfをどこのディレクトリに置くかという問題が新たに発生します。

ちょっとトリッキーで一部制約もありますが、shはまず間違いなく/binにあるので、gawkの場合、

#!/bin/sh
ZZ==1{ exec sh -c "cat $@ | gawk -f $0" ;}
awkスクリプト
。。。

で、大抵のケースは出来ると思います。上に書いたようにシェルからしか起動しないなら1行目は不要です。

ruby言語だとこういうことを想定してあって、#! ruby という行まで読み飛ばす -x というオプションがあります。この際、rubyに乗り換えては?
#!/bin/sh
exec ruby -S -x $0 $@
#! ruby
rubyスクリプト
。。。
    • good
    • 0
この回答へのお礼

> ・・・というのはbash等のシェルの機能じゃなくてOSカーネルの機能です。

そうだったのですね!今まで、呪文のように意味も分からず #! と書いていました。賢くなりました。

> >・env がスペース付き引数に対応する
>env は元々、・・・こういう変更はありえないです。

なるほど。すごく納得しました。

この件について質問があるので、新しい質問をたてます。
ありがとうございました!!

お礼日時:2006/01/01 10:14

バグレポートに返事が返ってきました。


#!構文にはひとつのインタプリタ言語しか置けずenv commandがスペースで区切られた構文(gawk -f)を一個のファイルとして認識してしまうのは、バグではなくPOSIXの仕様によるものだとのことです。私のパッチはこれを分離し、コマンド(gawk)と引数(-f)に分離するものでしたが、却下されてしまいました。

仕様ならしかたないですが、便利なものは仕様がどうあれ浸透するものです。あとでほとんどbashの機能をパクッた#! line用スパーインタプリターを作りたいなどとひそかに思っています。
-- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< -- 8< --
Traditional systems that parse #! lines can only give a single
argument to the interpreter being invoked. This is not a
feature of env, but of the operating system. That explains why
env is getting "awk -f" as a single argument. Unfortunately,
POSIX prohibits env from performing whitespace word
splitting on its arguments, so while the effort of your patch
is appreciated, it probably will not be applied. See the
POSIX requirements on env here:

http://www.opengroup.org/onlinepubs/009695399/ut …

When using /usr/bin/env as the interpreter in a #! line, you must
be sure that there is only one more word on the line, which means
that you cannot use env to invoke another program while still
providing arguments to that program.

この回答への補足

ありがとうございます!
パッチが書けるのですね。。すごい・・・

方法としては、
・env がスペース付き引数に対応する
もしくは
・"gawk -f" に対応するコマンド gawkf (?)を用意する(gawk -f を一つの引数にするため)
といった感じでしょうか・・

補足日時:2005/12/31 16:46
    • good
    • 0

>#!/usr/bin/env gawk -f



>とやってみたのですが、

>/usr/bin/env: gawk -f: No such file or directory
>と怒られます。なぜでしょうか・・

envのバグのようです。
ソースを取ってきてパッチしたら、動くようになりました。さーてと、バグレポートを書こうかな。
    • good
    • 0

#!/usr/bin/env bash


で、どうでしょうか?
(すべての環境でOKとは言い切れませんが、
たいていの場合、これで良いとおもいます。)

この回答への補足

ありがとうございます!
これは目から鱗な情報ですね。

env bash というのはどういう意味なのでしょうか?

補足日時:2005/12/30 12:49
    • good
    • 0
この回答へのお礼

すみません。調子に乗って gawk のスクリプトについても

#!/usr/bin/env gawk -f

とやってみたのですが、

/usr/bin/env: gawk -f: No such file or directory
と怒られます。なぜでしょうか・・

お礼日時:2005/12/30 12:52

UNIXやLinuxはそういう仕組みになっているので仕方ありません。


Tcl/Tkの場合も、
#!/bin/sh
# The next line restarts using wish \
exec wish "$0" "$@"
と書かなくちゃならないのですが、Windowsで動作させる場合はこの三行は不要なんですね。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!