次のスクリプト()が混乱していますhello.go
。
//usr/bin/env go run $0 $@ ; exit
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
実行する準備ができました。 (MacOS X 10.9.5)
$ chmod +x hello.go
$ ./hello.go
hello, world
で始まるシャーバンについて聞いたことがありません//
。スクリプトの上部に空白行を挿入しても機能します。このスクリプトが機能するのはなぜですか?
答え1
それはshebangではなく、単にデフォルトのシェルで実行されるスクリプトです。シェルは最初の行を実行します
//usr/bin/env go run $0 $@ ; exit
これはgo
ファイル名で呼び出しを行い、結果としてファイルがgoスクリプトとして実行され、ファイルの残りの部分を見ずにシェルが終了します。
//
しかし、なぜ正当な、または/
適切なshebangで始まるのですか#!
?
これは、ファイルが有効なgoスクリプトである必要があるためです。それ以外の場合は、goでエラーが発生します。 Goでは、これらの文字は//
コメントを表しているため、goは最初の行をコメントとして扱い、それを解釈しようとしません。ただし、この文字は#
コメントを表していないため、通常のshebangではgoがファイルを解釈するとエラーが発生します。
この構文を使用する理由は、単に踏むことなくシェルスクリプトとgoスクリプトであるファイルを構築するためです。
答え2
実行可能ファイルはデフォルトで/bin/shスクリプトと見なされるため、実行されます。つまり、特定のシェルを指定しないと #!/bin/sh になります。
// はパスでは無視されます。単一の「/」として扱うことができます。
したがって、自分がシェルスクリプトの最初の行を持っていると考えることができます。
/usr/bin/env go run $0 $@ ; exit
この行は何をしますか? "go run $0 $@" パラメーターを使用して "env" を実行します。ここで、「go」はコマンド、「run $ 0 $ @」はパラメータで、スクリプトを終了します。 $ 0はスクリプト名です。 $ @は元のスクリプトパラメータです。したがって、この行は go を実行し、引数とともにこのスクリプトを実行します。
コメントで指摘したように、非常に興味深い詳細があり、2つのスラッシュが実装定義されており、スクリプトが3つ以上のスラッシュを指定すると、スクリプトはPOSIXに収まります。引用するhttp://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.htmlパスでスラッシュを処理する方法の詳細。
また、$ @スクリプトに別のバグがあることに注意してください。 「$@」を使うのが正しい。そうしないと、パラメータにスペースが含まれていると複数のパラメータに分割されます。たとえば、「$ @」を使用しない限り、スペースを含むファイル名を渡すことはできません。
この特定のスクリプトは、明らかに「//」が「/」に等しいという考えに依存しています。
答え3
これはC ++(またはCがコメントを受け入れる場合は// C)で機能します。
//usr/bin/env sh -c 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null && $p'; exit