왜“#”에서“-”인가! / bin / sh-”shebang?


27
#! / bin / sh-

에 의해 스크립트를 해석 하도록 권장되는 shebang 은 종종 (또는 적어도) 권장 됩니다 /bin/sh.

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

그게 뭐야 -?

답변:


37

그 이유는 다음과 같이 작성해야합니다.

rm -- *.txt

그리고 아닙니다

rm *.txt

.txt현재 디렉토리 의 어떤 파일도로 시작하는 이름을 보장하지 않는 한 -.

에서:

rm <arg>

<arg>로 시작하면 옵션으로 간주 -되거나 그렇지 않으면 제거 할 파일로 간주됩니다. 에서

rm- <arg>

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치료 -로 및 끝 옵션 선행 getopt()과의 일반적인 사용하는 것은 --오랜 시간에 따라 옵션의 끝을 표시합니다. Bourne 쉘 (70 년대 후반)이 인수를 구문 분석하는 방식으로 옵션이 시작된 경우 첫 번째 인수 만 고려되었습니다 -. 이후의 모든 문자 -는 옵션 이름으로 취급됩니다. 뒤에 문자 -가 없으면 옵션이 없었습니다. 멈 췄고 이후의 Bourne과 같은 껍질 -은 옵션의 끝을 표시하는 방법으로 인식 됩니다.

Bourne 쉘에서 (그러나 현대 Bourne과 같은 쉘에서는 아님) #! /bin/sh -euf옵션에 대한 첫 번째 인수 만 고려되었으므로 문제를 해결할 수도 있습니다.

이제 우리는 여기에 현란한 존재라고 말할 수 있으며, 위의 기울임 꼴로 필요성 을 쓴 이유이기도합니다 .

  1. 올바른 생각을 가진 사람은 무언가로 시작 -하거나 +이름이 -또는로 시작되는 디렉토리에 스크립트를 넣지 않습니다 +.
  2. 그들이 한 경우에도 첫 번째는 스스로를 비난 할 수 있다고 주장 할뿐만 아니라 스크립트를 호출 할 때 쉘 또는 execvp()/ execlp()유형 함수 에서 발생하는 경우가 더 많습니다 . 그리고이 경우, 일반적으로 그들을 호출 중 하나로 the-script이에서보고되기 위해서는 $PATH이 경우의 경로 인수 execve()시스템 호출은 일반적으로 시작됩니다 /(하지 -않고 +) 또는 ./the-script당신이 원하는 경우 the-script현재 디렉토리에서 실행하는 (그리고 다음 경로로 시작 ./하지, -+) 중 하나.

이제 이론적 정확성 문제 옆에 모범 사례#! /bin/sh - 로 추천 된 또 다른 이유 가 있습니다 . 그리고 여러 시스템이 여전히 setuid 스크립트를 지원했던 시점으로 돌아갑니다.

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

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

그리고 그 스크립트는 -r-sr-xr-x root bin일반 사용자가 실행할 때 해당 시스템에서 setuid root ( 권한 과 같은)입니다 .

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

로 수행됩니다 root!

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

-(는 주위에 작동하지 않을 것이라는 점을 해결할 것이다 경쟁 조건 문제 , 또는 사실 sh일부처럼 구현 ksh88기반 것들 않고 스크립트 인수를 조회 할 /$PATH생각을).

요즘은 거의 모든 시스템 지원이 setuid 스크립트 더 이상하고 (안 기본적으로 보통) 아직도 그들 중 일부는, 일 최대 종단 A execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])(여기서 <n>주위에이 문제와 모두 작동하는 스크립트를 읽기위한 열린 파일 기술자입니다) 경쟁 조건.

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

또한

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

다음 인수는 인수로 간주됩니다으로 문제가없는 -f어떤 경우에 옵션,하지만 경우 여전히 일을하지 않는 path/to/script것입니다 -(이 경우, 가장 sed/ awk구현 sed/ awk로부터의 코드를 읽지 않는다 -파일이지만 stdin에서 대신).

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

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

대부분의 시스템에서 shebang 메커니즘은 인터프리터 경로 다음에 하나의 인수 만 허용 합니다.

#! /bin/sh -vs 사용 여부에 #!/bin/sh -관해서는 맛의 문제 일뿐입니다. 나는 인터프리터 경로를 더 잘 보이게하고 마우스 선택을 쉽게하기 때문에 전자를 선호합니다. 있다 공간이 고대의 유닉스 버전에 필요하다고 말한다 전설 되지만 확인 된 적이 AFAIK는.

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


1
이것은 #! / bin / bash와 관련이 있습니까?
Joe

1
물론 @Joe bash는 다른 모든 쉘과 같은 옵션을 허용합니다. 하는 본 같은과 POSIX 쉘 인, bash모두 수용 #! /bin/bash -하고 #! /bin/bash --.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.