인터프리터는 #! / bin / sh를 읽습니까?


66

에서 bash또는 sh, 나는 시작 아무것도 추측 #A는 코멘트를 .

그러나 bash스크립트에서 우리는 다음과 같이 씁니다.

#!/bin/bash

그리고 파이썬 스크립트에는 다음이 있습니다.

#!/bin/python

이것은 #그 자체로는 주석이지만 #!그렇지 않은 것을 의미합니까 ?


1
Apparmor 프로파일을보기 시작하면이 나타납니다 #include. 거기에도 역시 #주석이 아닙니다.

4
@ vasa1 그러나 종종 쉘 스크립트의 시작 부분에 hashbang 라인에 대한 평가 아니에요 키 포인트는 것입니다 그들이 있는 코멘트 .
Eliah Kagan

답변:


100

#!줄은 스크립트가 실행 되기 전에 사용 된 다음 스크립트가 실행될 무시 됩니다.

당신은 shebang 라인 과 일반적인 주석 의 차이점이 무엇인지 묻습니다 .

로 시작하는 행은로 시작 #!하는 다른 행과 마찬가지로 주석입니다 #. 이 #!파일의 첫 번째 줄이거 나 다른 곳인 경우에도 마찬가지입니다. #!/bin/sh 영향 을 주지만 , 인터프리터 자체는 읽지 않습니다 .

#는 모든 프로그래밍 언어의 주석은 아니지만, 아시다시피, shbash( 및 대부분의 Bourne 스타일이 아닌 쉘과 같은 csh) Bourne 스타일 쉘의 주석입니다 . 또한 파이썬의 주석이기도합니다 . 그리고 실제로 스크립트가 아닌 다양한 구성 파일의 주석입니다 (예 /etc/fstab:).

쉘 스크립트가로 시작한다고 가정하십시오 #!/bin/sh. 그것은 주석이며, 인터프리터 (쉘)는 #문자 뒤의 줄에있는 모든 것을 무시 합니다.

#!라인 의 목적은 통역사에게 정보를 제공 하는 것이 아닙니다. #!라인 의 목적은 운영 체제 (또는 인터프리터를 시작하는 모든 프로세스) 에게 인터프리터 로 사용할 것을 알려주는 것 입니다.

  • 예를 들어을 실행하여 스크립트를 실행 파일로 호출하면 ./script.sh시스템은 첫 번째 행을 참조하여로 시작하는지 #!, 공백이 0 개 이상인지, 명령 이 있는지 확인합니다 . 그럴 경우 스크립트 이름을 인수로 사용하여 해당 명령을 실행합니다. 이 예에서는 /bin/sh script.sh(또는 기술적으로 /bin/sh ./script.sh) 실행됩니다 .

  • 인터프리터를 명시 적으로 호출하여 스크립트를 호출하면 #!라인이 참조되지 않습니다. 따라서을 실행 sh script.sh하면 첫 번째 줄은 효과가 없습니다. 경우 script2.sh의 첫 번째 줄은 #!/usr/games/nibbles, 달리기 sh script2.sh에서 스크립트를 열려고하지 않을 것이다 nibbles(하지만 ./script2.sh것입니다).

두 경우 모두 스크립트의 확장 ( .sh)이 있으면 실행 방법에 영향을 미치지 않습니다. 유닉스 계열 시스템에서는 일반적으로 스크립트 실행 방법에 영향을 미치지 않습니다. Windows와 같은 다른 시스템에서는 #!shebang 행이 시스템에서 완전히 무시 될 수 있으며 확장 프로그램에서 스크립트를 실행할 항목을 결정할 수 있습니다. (이것은 스크립트 확장명을 제공 할 필요는 없지만, 그렇게하면 스크립트가 올바른 이유 중 하나입니다.)

#!주석을 시작 하기 때문에이 목적을 정확하게 수행하도록 선택되었습니다 #. 이 #!줄은 통역사가 아닌 시스템을위한 것이며 통역사가 무시해야합니다.

Bash 스크립트를위한 Shebang 라인

당신은 (원래) 사용했다 #!/bin/sh위한 bash스크립트. 스크립트에 bash확장자 sh가 필요하지 않은 경우에만 스크립트 를 실행할 수 있어야합니다. sh항상에 대한 심볼릭 링크는 아닙니다 bash. 종종 포함한 모든 원격 최근 데비안과 우분투 시스템 , sh에 심볼릭 링크입니다 dash.

Python 스크립트 용 Shebang 라인

또한 (편집하기 전에 질문의 첫 번째 버전에서)로 Python 스크립트를 시작한다고 말했습니다 #!/bin/sh read by the interpretor. 당신이 말 그대로 그 의미라면, 그 일을 중단해야합니다. hello.py해당 줄로 시작 하면 running ./hello.py은 다음을 실행합니다.

/bin/sh read by the interpretor hello.py

/bin/shread( by the interpretor hello.py인수 와 함께) 라는 스크립트를 실행하려고 시도하며 , read희망적으로는 찾을 수 없으며 Python 인터프리터는 Python 스크립트를 볼 수 없습니다.

이 실수를하고 있지만 내가 설명하는 문제가 없다면, 인터프리터 (예 :)를 명시 적으로 지정 python hello.py하여 첫 번째 줄이 무시되도록 파이썬 스크립을 호출했을 것입니다 . 스크립트를 다른 사람에게 배포하거나 나중에 오래 사용하면 스크립트가 작동하는 데 필요한지 확실하지 않을 수 있습니다. 지금 수정하는 것이 가장 좋습니다. 또는 적어도 첫 번째 줄을 완전히 제거 ./하면 오류 메시지 와 함께 실행되지 않을 때 의미가 있습니다.

파이썬 스크립트의 경우, 파이썬 인터프리터가 어디에 있는지 (혹은 앞으로 있을지) 알면 #!같은 방식으로 줄을 작성할 수 있습니다 .

#!/usr/bin/python

그것은 파이썬 3 스크립트가 있는지 또는, 당신은 지정해야 python3하기 때문에, python거의 항상 파이썬 2 :

#!/usr/bin/python3

그러나 문제는 /bin/sh항상 존재해야 하며 OS와 함께 제공 /bin/bash되는 시스템에는 거의 항상 존재한다는 bash것입니다. 파이썬은 다양한 장소에 존재할 수 있습니다.

따라서 많은 파이썬 프로그래머는 이것을 대신 사용합니다.

#!/usr/bin/env python

(또는 #!/usr/bin/env python3Python 3의 경우)

이렇게하면 스크립트 env가 올바른 위치에 의존하는 대신 "적절한 위치"에 의존하게됩니다 python. 다음과 같은 이유로 좋은 것입니다.

  • env거의 항상에 있습니다 /usr/bin.
  • 대부분의 시스템에서 스크립트를 실행 python 해야하는 것은 시스템에서 가장 먼저 나타나는 것 PATH입니다. make run으로 시작 hello.py하는 (가상) running과 같습니다 .#!/usr/bin/env python./hello.py/usr/bin/env python hello.pypython hello.py

사용할 수없는 이유 #!python는 다음과 같습니다.

  • 지정된 인터프리터가 절대 경로 (예 :로 시작 /) 로 제공되기를 원합니다 .
  • 호출 프로세스는 python 현재 디렉토리에서 실행 됩니다 . 명령에 슬래시가 포함되지 않은 경우 경로를 검색하는 것은 특정 쉘 동작입니다.

때때로 쉘 스크립트가 아닌 Python 또는 기타 스크립트 는 다른 코드가 있는 #!/bin/sh ...곳에서 시작되는 shebang 줄을 갖습니다 .... sh파이썬 인터프리터를 호출하기 위해 인수와 함께 Bourne 호환 쉘 ( ) 을 호출하는 방법이 있기 때문에 때때로 올바른 것입니다. (인수 중 하나에 아마도을 포함 할 것입니다 python.) 그러나 대부분의 #!/usr/bin/env python경우 단순하고 우아하며 원하는 방식으로 작동 할 가능성이 높습니다.

다른 언어로 된 세방 라인

많은 프로그래밍 및 스크립팅 언어 및 기타 파일 형식 #이 주석으로 사용 됩니다. 이들 중 하나의 경우, 첫 번째 행에 프로그램을 지정하여 파일을 인수로 사용하는 프로그램이 언어로 된 파일을 실행할 수 있습니다 #!.

일부 프로그래밍 언어에서 #일반적으로 주석은 아니지만 특수한 경우 첫 줄은로 시작하면 무시됩니다 #!. 주석 을 #!달지 않아도 구문을 쉽게 사용할 수 있습니다 #.

스크립트로 실행되지 않는 파일의 Shebang 라인

직관적이지 않지만 파일 형식이 첫 번째 줄부터 시작 #!하여 실행 파일의 전체 경로를 수용 할 수있는 파일은 shebang 줄을 가질 수 있습니다. 이 작업을 수행하고 파일이 실행 가능으로 표시되면 파일처럼 문서처럼 열리도록 프로그램처럼 실행할 수 있습니다.

일부 응용 프로그램은이 동작을 의도적으로 사용합니다. 예를 들어, VMware에서 .vmx파일은 가상 머신을 정의합니다. 가상 머신은 스크립트처럼 가상 머신을 "실행"할 수 있습니다. 이러한 파일은 실행 가능으로 표시되어 있으며 가상 머신이 VMware 유틸리티에서 열립니다.

스크립트로 실행되지 않고 스크립트처럼 작동하는 파일의 Shebang 라인

rm파일을 제거합니다. 스크립트 언어가 아닙니다. 그러나 #!/bin/rm실행 파일로 시작 하고 표시된 파일을 실행할 수 있으며 실행할 때 파일을 rm호출하여 삭제합니다.

이것은 종종 "파일 자체 삭제"로 개념화됩니다. 그러나 파일이 실제로 실행되고 있지 않습니다. 이것은 .vmx파일에 대해 위에서 설명한 상황과 비슷 합니다.

#!행은 간단한 명령 (명령 줄 인수 포함)의 실행을 용이하게하기 때문에 이런 식으로 일부 스크립팅을 수행 할 수 있습니다. 보다 복잡한 "스크립트"의 간단한 예로 다음을 #!/bin/rm고려하십시오.

#!/usr/bin/env tee -a

이것은 사용자 입력을 대화식으로 가져 와서 한 줄씩 다시 에코하여 "스크립트"파일의 끝에 추가합니다.

유능한? 하지 매우. 개념적으로 흥미로운가요? 전적으로! 예. (약간.)

개념적으로 유사한 프로그래밍 / 스크립트 개념 (재미를 위해)


@Rinzwind Thx! (그렇지만 궁금한 점이 있다면이 답변이 다른 곳에서는 나오지 않습니다.)
Eliah Kagan

@Rinzwind 걱정하지 마십시오. 1 시간 후 8 개의
공감 률로 인해

1
항상 무시한다면 파이썬 -x플래그는 무엇을합니까?
gerrit

4
@gerrit 좋은 질문입니다. 정수 / 컴파일러가 행 번호가있는 메시지를보고하는 모든 언어에서 주석 내용 은 무시되지만 주석 행은 계속 계산됩니다 . 코드 줄 앞에 주석이나 빈 줄을 추가하면 줄 번호가 늘어난 코드 줄이 계속 나타납니다. -x"[S] 첫 번째 줄 ... 스킵"제 2 라인은 번호가됩니다 1대신 2, 3 라인 2대신을 3당신이 플래그를 사용하지 말아야하는 이유이다 등. ;) -x은 shebang과 같은 구문으로 시작하지 않는 Unix와 같은 OS가 아닌 스크립트에서 작성합니다 #(따라서 Python 주석이 아님).
Eliah Kagan

4
Perl에서 인터프리터가 직접 시작된 경우 ( perl script.plvs ./script.pl) 인터프리터 shebang 행을 읽고와 같은 플래그를 구문 분석합니다 -w. 그래도이 기능에 의존하지 않는 것이 좋습니다.
OrangeDog

7

shebang은 스크립트의 첫 줄에서 처음 두 문자로 나타날 때 문자 번호 부호와 느낌표 (예 : "#!")로 구성된 문자 순서입니다.

* nix 운영 체제에서 shebang으로 시작하는 스크립트가 실행될 때 프로그램 로더는 나머지 스크립트의 초기 행을 해석기 지시문으로 구문 분석합니다. 지정된 인터프리터 프로그램이 대신 실행되어 스크립트를 실행할 때 처음에 사용 된 경로를 인수로 전달합니다. 예를 들어, 스크립트 이름이 "path / to / your-script"경로로 지정되고 다음 줄로 시작하는 경우 :

#!/bin/sh

프로그램 로더는 "path / to / your-script"를 첫 번째 인자로 전달하는 대신 Bourne 쉘 또는 호환 쉘과 같이 "/ bin / sh"프로그램을 실행하라는 지시를받습니다.

따라서 스크립트는 "path / to / python-script"경로로 이름이 지정되며 다음 줄로 시작합니다.

#!/bin/python

로드 된 프로그램은 "path / to / python-script"를 첫 번째 인수로 전달하는 대신 파이썬 인터프리터와 같이 프로그램 "/ bin / python"을 실행하도록 지시됩니다.

간단히 말해서 "#"은 문자 순서 "#!"동안 줄을 주석 처리합니다. 스크립트의 첫 줄에서 처음 두 문자로 나타나는 것은 위와 같은 의미를 갖습니다.

자세한 내용은 일부 스크립트가 #으로 시작하는 이유 를 참조하십시오 . ...?

출처 : 이 답변의 일부 섹션에서 (약간의 수정과 함께) 파생 오두막 (유닉스) 에서 영어 위키 백과 (가 위키 백과 기여자 ). 이 문서는 AU의 사용자 콘텐츠와 동일하게 CC-BY-SA 3.0 에 따라 사용이 허가되므로이 파생물은 저작자 표시가 허용됩니다.


4

#!shebang스크립트의 첫 줄에 처음 두 문자로 나타날 때를 호출합니다 . 스크립트에서 실행을위한 인터프리터를 나타내는 데 사용됩니다. 은 shebang하지 쉘의 운영 체제 (커널)입니다; 주석으로 해석되지 않습니다.

예의 : http://en.wikipedia.org/wiki/Shebang_%28Unix%29

일반적으로 파일이 실행 가능하지만 실제로는 실행 가능 (이진) 프로그램이 아니고 해당 행이있는 경우 프로그램은 #! 스크립트 이름과 모든 인수로 시작됩니다. 이 두 문자 #와! 파일에서 처음 2 바이트 여야합니다!

자세한 정보 : http://wiki.bash-hackers.org/scripting/basics#the_shebang


0

아니요, execLinux 커널 의 시스템 호출 에서만 사용되며 인터프리터의 주석으로 처리됩니다.

bash에서 할 때 :

./something

Linux에서는 exec경로를 사용 하여 시스템 호출을 호출합니다 ./something.

이 커널 라인은 https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25에 전달 된 파일에서 호출됩니다 exec.

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

파일의 첫 바이트를 읽고와 비교합니다 #!.

비교가 참이면 나머지 행은 Linux 커널에 의해 구문 분석되어 exec경로 /usr/bin/env python와 현재 파일을 첫 번째 인수로 사용하여 다시 호출 합니다.

/usr/bin/env python /path/to/script.py

이것은 #주석 문자로 사용 되는 모든 스크립팅 언어에서 작동 합니다.

그리고 네, 당신은 무한 루프를 만들 수 있습니다 :

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

배시는 오류를 인식합니다.

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! 사람이 읽을 수 있지만 반드시 필요한 것은 아닙니다.

파일이 다른 바이트로 시작된 경우 exec시스템 호출은 다른 핸들러를 사용합니다. 다른 가장 중요한 기본 핸들러는 ELF 실행 파일입니다 : https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 바이트를 확인하는 7f 45 4c 46인간으로 발생하는 ( 에 읽을 수 있음 .ELF). /bin/lsELF 실행 파일 인의 첫 번째 4 바이트를 읽음으로써 확인하십시오 .

head -c 4 "$(which ls)" | hd 

산출:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

따라서 커널이 해당 바이트를 볼 때 ELF 파일을 가져 와서 메모리에 올바르게 넣고 새 프로세스를 시작합니다. 참조 : https : //.com/questions/8352535/how-does-kernel-get-an- executable-binary-file-running-under-linux / 31394861 # 31394861

마지막으로, binfmt_misc메커니즘을 사용하여 자체 Shebang 처리기를 추가 할 수 있습니다 . 예를 들어, 파일에 대한 사용자 정의 핸들러를.jar 추가 할 수 있습니다 . 이 메커니즘은 파일 확장자 별 핸들러도 지원합니다. 다른 응용 프로그램은 QEMU를 사용하여 다른 아키텍처의 실행 파일투명하게 실행하는 것 입니다.

POSIX가 shebang을 지정하지는 않는다고 생각합니다 : https://unix.stackexchange.com/a/346214/32558 비록 이론적 근거 섹션에 언급되어 있지만 "실행 가능한 스크립트가 시스템에서 지원되는 경우 우연히 있다".

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