다음 스크립트( )에 대해 혼란스럽습니다 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
로 시작하는 shebang에 대해 들어본 적이 없습니다 //
. 그리고 스크립트 상단에 빈 줄을 삽입해도 여전히 작동합니다. 이 스크립트가 작동하는 이유는 무엇입니까?
답변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를 실행합니다.
주석에서 지적한 것처럼 두 개의 슬래시가 구현에 따라 정의되고 이 스크립트가 세 개 이상의 슬래시를 지정하면 이 스크립트가 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