왜 "#!/bin/sh -" shebang에 "-"가 있나요?

왜 "#!/bin/sh -" shebang에 "-"가 있나요?
#! /빈/sh -

(또는 적어도) 종종 권장됩니다셰르본스크립트를 /bin/sh(또는 #! /bin/bash -bash, #! /bin/ksh -ksh 등) 로 해석하도록 합니다.

왜 그냥 #! /bin/sh또는 #!/bin/sh?

그게 뭔데 -?

답변1

이는 다음과 같이 작성해야 하는 이유와 유사합니다.

rm -- *.txt

설마

rm *.txt

.txt현재 디렉토리에 이름 이 -.

존재하다:

RM<매개변수>

<arg>파일로 시작하면 -옵션으로 간주되고, 그렇지 않으면 삭제할 파일로 간주됩니다. 존재하다

RM-<매개변수>

<arg>파일 시작 여부에 관계없이 항상 삭제 대상으로 간주됩니다 -.

에 대해서도 마찬가지입니다 sh.

실행할 때

#! /bin/sh

일반적으로 다음과 관련됩니다.

execve("path/to/the-script", ["the-script", "arg"], [environ])

시스템은 이를 다음으로 변환합니다.

execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])

이것path/to/the-script일반적으로 스크립트 작성자의 통제를 받지 않습니다. 작성자는 스크립트 복사본이 어디에 저장될지, 어떤 이름으로 저장될지 예측할 수 없습니다. 특히, 보장할 수는 없습니다.path/to/the-script호출이 시작되지 않는 경우 -(또는 +문제일 수도 있음 sh) 그래서 우리는필요이것 -으로 옵션이 끝났습니다.

예를 들어, 내 시스템에는 zcat(실제로 대부분의 다른 스크립트와 마찬가지로) 해당 조언을 ​​따르지 않는 스크립트의 예가 있습니다.

$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]

#! /bin/sh -이제 왜 안 되냐고 물으실 수도 있습니다 #! /bin/sh --.

#! /bin/sh --POSIX 쉘과 함께 사용할 수 있지만 특히 #! /bin/sh -고대 버전은 더 이전 버전 sh으로 간주 sh하고 옵션 종료를 오랫동안 표시하는 데 사용됩니다 . Bourne 쉘(70년대 후반부터)이 인수를 구문 분석하는 방식으로, 첫 번째 인수가 로 시작하면 이후의 모든 문자 는 옵션 이름으로 처리됩니다 . 이것이 멈추었고 Bourne과 같은 모든 후속 쉘은 이를 옵션의 끝을 표시하는 방법으로 처리했습니다.-getopt()------

Bourne 쉘(현대 Bourne과 유사한 쉘에서는 아님)에서는 #! /bin/sh -eu이 문제를 해결할 수도 있습니다. 옵션이 첫 번째 인수만 고려하기 때문입니다.

자, 어떤 사람들은 우리가 여기서 현학적이라고 말할 수도 있습니다. 이것이 제가 이 글을 쓰는 이유입니다.필요위의 이탤릭체:

  1. 올바른 생각을 가진 사람은 -또는 로 시작하는 스크립트를 호출하거나 +이름이 또는 로 시작하는 디렉토리에 스크립트를 넣지 않을 것입니다.-+
  2. 설령 그렇게 했다고 하더라도, 첫 번째 사람은 자신들이 책임을 져야 하며 스크립트를 호출할 때 일반적으로 쉘이나 execvp()/ execlp()유형 함수에서 발생한다고 주장할 것입니다. 이 경우 일반적으로 호출하여 the-script찾을 수 있습니다. $PATH이 경우 시스템 호출에 대한 경로 인수는 일반적으로 (not 또는 ) execve()로 시작 하거나 현재 디렉터리에서 실행 하려는 것과 같습니다 (그런 다음 경로는 , is not로 시작합니다. 그것도 아니고 ) 시작하세요./-+./the-scriptthe-script./-+

이제는 이론 외에단정#! /bin/sh -질문, 추천하는 또 다른 이유가 있습니다좋은 연습. 이는 여러 시스템이 여전히 setuid 스크립트를 지원하던 시절로 거슬러 올라갑니다.

다음을 포함하는 스크립트가 있는 경우:

#! /bin/sh
/bin/echo "I'm running as root"

스크립트는 -r-sr-xr-x root bin권한과 마찬가지로 setuid 루트이며 일반 사용자가 실행할 때 이러한 시스템에서는

execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])

완료됩니다 root!

사용자가 심볼릭 링크를 생성 /tmp/-i -> path/to/the-script하고 실행하면 대화형 쉘( )이 로 -i시작됩니다 ./bin/sh -iroot

이 문제를 해결할 수 -있습니다(해결할 수 없습니다경쟁 조건 문제, 또는 일부 sh구현(예: - 기반 구현은 in 없이 스크립트 매개변수를 찾습니다 ksh88)./$PATH

요즘에는 더 이상 setuid 스크립트를 지원하지 않는 시스템이 거의 없으며, 여전히 수행하는 일부 시스템(보통 기본적으로는 아님)은 이 문제와 콘테스트 조건을 해결하기 위해 스크립트를 읽기 위해 파일 설명자를 여는 작업을 수행하게 execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])됩니다 <n>.

Bourne과 같은 쉘뿐만 아니라 대부분의 인터프리터에서도 비슷한 문제가 발생합니다. Bourne과 유사하지 않은 쉘은 일반적으로 -옵션 끝 표시를 지원하지 않지만 일반적으로 지원합니다 --(적어도 최신 버전에서는).

반품

#! /usr/bin/awk -f
#! /usr/bin/sed -f

문제 없습니다. 어떤 경우든 다음 인수는 옵션에 대한 인수로 간주되지만, -f그렇다면 여전히 작동하지 않습니다(이 경우 대부분의 / 구현에서 /는 파일에서 나오지 않고 표준에서 나옵니다). 입력하다).path/to/script-sedawksedawk-

또한 대부분의 시스템에서는 다음을 사용할 수 없습니다.

#! /usr/bin/env sh -
#! /usr/bin/perl -w --

대부분의 시스템과 마찬가지로 shebang 메커니즘은 다음만 허용합니다.하나인터프리터 경로 뒤에 오는 매개변수입니다.

#! /bin/sh -VS를 사용할지 #!/bin/sh -여부는 단지 취향의 문제일 뿐입니다. 나는 인터프리터 경로를 더 명확하게 만들고 마우스 선택을 더 쉽게 하기 때문에 전자를 선호합니다. 하나 있다전설에 따르면 일부 고대 버전의 Unix에는 이 공간이 필요했습니다.그러나 내가 아는 한 이것은 확인된 적이 없습니다.

Unix shebang에 대한 아주 좋은 참고 자료는 다음에서 찾을 수 있습니다.https://www.in-ulm.de/~mascheck/various/shebang


1 사용하더라도 추가 작업을 zsh수행할 수 있으며 옵션의 끝을 표시할 수도 있습니다.#! /bin/zsh -eu--

관련 정보