`//`로 시작하는 Shebang?


60

스크립트 ( 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에 대해들은 적이 없습니다 //. 그리고 스크립트 상단에 빈 줄을 삽입해도 여전히 작동합니다. 이 스크립트는 왜 작동합니까?


//&>/dev/null;x="${0%.*}";[ ! "$x" -ot "$0" ]||(rm -f "$x";cc -o "$x" "$0")&&exec "$x" "$@" ...
REINSTATE MONICA-제레미 뱅크스

2
아래의 @ g-man 및 Jörg 의견에 이어 gilles answer ( unix.stackexchange.com/a/1919/27616 )에 따르면이 트릭은 가장 호환되는 ///....대신 사용해야 합니다 //...!
Olivier Dulac

1
따옴표없이 공백이있는 인수 (또는 디렉토리의 위치)를 올바르게 처리하지 못합니다.go run "$0" "$@"
Charles Duffy

답변:


71

그것은 shebang이 아니며 기본 쉘에 의해 실행되는 스크립트 일뿐입니다. 쉘은 첫 번째 줄을 실행

//usr/bin/env go run $0 $@ ; exit 

이는 원인 go이 파일의 이름으로 호출 할, 그래서 결과는이 파일이 파일의 나머지 부분을 보지 않고 다음 쉘 종료 갈 스크립트로 실행된다는 점이다.

그러나 왜 //그냥 /또는 적절한 shebang 대신 시작 #!합니까?

파일이 유효한 go 스크립트 여야하거나 go가 불평하기 때문입니다. go에서 문자 //는 주석을 나타내므로 go는 첫 번째 행을 주석으로보고 해석하지 않습니다. 그러나 문자 #는 주석을 나타내지 않으므로 일반 shebang은 파일을 해석 할 때 오류가 발생합니다.

이 구문의 이유는 쉘 스크립트와 go 스크립트 인 파일을 빌드하는 것입니다.


10
쉘이 아닌 커널에 의해 처리됩니다. Linux가 다중 경로 구분 기호 (/ home //// username /// file)를 처리하는 방법에 대한 Gilles의 답변을 참조하십시오 .
G-Man

3
@HermanTorjussen Feature – 경로의 시너스는 꽤 잘 정의되어 있으며, 많은 유용한 변형을 허용하며, 힘은 복잡합니다. /경로 접미어는 /.; 때 a심볼릭 링크 아니라, a같은입니다 a/같은 인 a/.테라는 경로가 추가로 얻을 수있는 경우입니다 /의미의 변화없이가. 정식 경로를 도출 할 때 연속 슬래시를 하나로 축소하는 정규화 단계가 있습니다. 그러나 공식 구문의 깔끔한 부분은 아닙니다.
Volker Siegel

13
실제로 POSIX는 경로의 맨 처음에 정확히 두 개의 슬래시가있는 경우를 제외하고 여러 슬래시가 단일 슬래시와 동일하다고 말합니다 . 여기에서와 같이. 이 경우 경로 해석은 구현에 따라 다릅니다. "경로 이름이 두 개의 연속 <슬래시> 문자로 시작하는 경우 선행 <슬래시> 문자 다음에 오는 첫 번째 구성 요소는 구현 정의 방식으로 해석 될 수 있습니다. 두 개의 선행 <슬래시> 문자는 단일 <슬래시> 문자로 취급됩니다. "
Jörg W Mittag

11
따라서 이식성을 ///usr/bin/env go run $0 $@ ; exit
Ruslan

1
@geek 쉘은 종료되지만 go 인터프리터를 시작하기 전에는 종료되지 않습니다. Go는 쉘이 아닌 hello world를 인쇄합니다.
케이시

8

기본적으로 실행 파일은 / bin / sh 스크립트로 가정되기 때문에 실행됩니다. 즉, 특정 쉘을 지정하지 않은 경우 #! / bin / sh입니다.

//는 경로에서 무시됩니다. 단일 '/'로 간주 할 수 있습니다.

따라서 첫 줄에 쉘 스크립트가 있다고 생각할 수 있습니다.

/usr/bin/env go run $0 $@ ; exit

이 라인은 무엇을합니까? paramenters 'go run $ 0 $ @'와 함께 'env'를 실행합니다. 'go'는 명령이고 'run $ 0 $ @'은 인수이며 스크립트를 종료합니다. 이 스크립트 이름은 $ 0입니다. $ @는 원래 스크립트 인수입니다. 이 줄은이 스크립트를 실행합니다.

주석에서 알 수 있듯이 두 개의 슬래시가 구현 정의되어 있으며이 스크립트가 세 개 이상의 슬래시를 지정하면 POSIX로 수정됩니다. 경로에서 슬래시를 처리하는 방법에 대한 자세한 내용은 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html 을 참조하십시오 .

스크립트에서 $ @에 또 다른 실수가 있습니다. 그렇지 않으면 매개 변수에 공백이 있으면 많은 매개 변수로 분할되므로 "$ @"를 대신 사용하는 것이 좋습니다. 예를 들어 "$ @"를 사용하지 않으면 파일 이름을 공백으로 전달할 수 없습니다

이 특정 스크립트는 분명히 '//'가 '/'와 동일하다는 생각에 의존합니다.


9
"//는 경로에서 무시됩니다"– 보장되지 않습니다 : "경로 이름이 두 개의 연속 <slash> 문자로 시작하는 경우 선행 <slash> 문자 다음에 오는 첫 번째 구성 요소는 구현 정의 방식으로 해석 될 수 있습니다"( pubs .opengroup.org / onlinepubs / 9699919799 / basedefs /… )
Jörg W Mittag

매우 흥미롭고 업데이트 된 답변.
gena2x

1
... AFS는 특히 // 다르게 구현되었지만 더 이상 일반적이지 않습니다.
Charles Duffy

0

이것은 C ++에서 작동하며 C가 주석을 허용하는 경우 C입니다.

//usr/bin/env sh -c 'p=$(expr '"_$0"' : "_\(.*\)\.[^.]*"); make $p > /dev/null && $p'; exit

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.