[python] 사람들이 왜 파이썬 스크립트의 첫 줄에 #! / usr / bin / env python shebang을 작성합니까?

그 줄없이 파일이 동일하게 실행되는 것처럼 보입니다.



답변

여러 버전의 Python이 설치되어 있으면 /usr/bin/env사용되는 인터프리터가 환경의 첫 번째 인터프리터인지 확인하십시오 $PATH. 대안은 다음과 같은 것을 하드 코딩하는 것입니다 #!/usr/bin/python. 괜찮지 만 유연성은 떨어집니다.

유닉스에서, 해석 되는 실행 파일 #!은 첫 줄의 시작 부분에 인터프리터 (및 필요한 플래그)를 붙여서 어떤 인터프리터를 사용해야하는지 나타낼 수 있습니다 .

당신이 다른 플랫폼에 대해 얘기하는 경우, 물론,이 규칙이 적용되지 않습니다 (하지만 “오두막 라인은”아무런 해를 끼치 지 않으며, 혹시 플랫폼에 해당 스크립트를 복사하면 도움이 될 것입니다 같은 리눅스, 맥 등의 유닉스 기반, 등).


답변

이것을 세방 라인 이라고합니다 . 현상태대로 위키 백과 항목을 설명합니다 :

컴퓨팅에서 shebang (해시 뱅, hashpling, pound bang 또는 crunchbang이라고도 함)은 “#!”문자를 나타냅니다. 텍스트 파일의 첫 번째 행으로 인터프리터 지시문에서 처음 두 문자 인 경우 유닉스 계열 운영 체제에서 프로그램 로더는 파일이 스크립트임을 나타내는 표시로이 두 문자가 존재하고 파일의 첫 번째 행에 지정된 인터프리터를 사용하여 해당 스크립트를 실행하려고합니다.

유닉스 FAQ 항목 도 참조하십시오 .

shebang 행이 인터프리터를 실행할 것으로 판별하지 않는 Windows에서도 shebang 행에 옵션을 지정하여 인터프리터에 옵션을 전달할 수 있습니다. 일회성 스크립트 (예 : 질문에 대답 할 때 쓰는 스크립트)에 일반 shebang 줄을 유지하는 것이 유용하므로 Windows 및 ArchLinux 모두에서 빠르게 테스트 할 수 있습니다 .

ENV 유틸리티를 사용하면 경로에 명령을 호출 할 수 있습니다 :

첫 번째 나머지 인수는 호출 할 프로그램 이름을 지정합니다. PATH환경 변수 에 따라 검색됩니다 . 나머지 인수는 해당 프로그램에 인수로 전달됩니다.


답변

다른 답변을 조금 확장하면 다음과 같이 /usr/bin/env셰방 라인 을 신중하게 사용하여 명령 줄 스크립트가 어떻게 문제를 일으킬 수 있는지에 대한 작은 예가 있습니다 .

$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py
Traceback (most recent call last):
  File "./my_script.py", line 2, in <module>
    import json
ImportError: No module named json

json 모듈은 Python 2.5에 없습니다.

이러한 종류의 문제를 방지하는 한 가지 방법은 일반적으로 대부분의 Python과 함께 설치되는 버전이 지정된 python 명령 이름을 사용하는 것입니다.

$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"

Python 2.x와 Python 3.x를 구별해야하는 경우 최신 릴리스의 Python 3에서도 python3이름을 제공합니다 .

$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")


답변

파이썬 스크립트를 실행하려면 쉘에 세 가지를 알려야합니다.

  1. 파일이 스크립트임을
  2. 스크립트를 실행하려는 인터프리터
  3. 상기 통역사의 경로

shebang은 #!달성합니다 (1.). 문자는 많은 스크립팅 언어에서 주석 마커 #이기 때문에 shebang은로 시작 #합니다. 따라서 shebang 행의 내용은 인터프리터에 의해 자동으로 무시됩니다.

env명령은 (2.)와 (3.)을 달성합니다. “창의력”을 인용하면

env명령 의 일반적인 용도는 env가 $ PATH를 검색하여 명령을 실행한다는 사실을 이용하여 인터프리터를 시작하는 것입니다. shebang 행에는 절대 경로를 지정해야하며 다양한 인터프리터 (perl, bash, python)의 위치가 다양 할 수 있으므로 다음을 사용하는 것이 일반적입니다.

#!/usr/bin/env perl  / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl, / fileserver / usr / bin / perl 또는 / home인지 추측하는 대신 사용자 시스템의 / MrDaniel / usr / bin / perl …

반면, env는 거의 항상 / usr / bin / env에 있습니다. (그렇지 않은 경우를 제외하고; 일부 시스템은 / bin / env를 사용할 수 있지만 상당히 드문 경우이며 Linux 이외의 시스템에서만 발생합니다.)


답변

아마도 귀하의 질문은 다음과 같은 의미입니다.

사용하려는 경우 : $python myscript.py

그 줄은 전혀 필요하지 않습니다. 시스템은 파이썬을 호출하고 파이썬 인터프리터는 스크립트를 실행합니다.

그러나 사용하려는 경우 : $./myscript.py

일반 프로그램이나 bash 스크립트처럼 직접 호출하면 해당 라인을 작성하여 프로그램을 실행하는 데 사용하는 시스템에 지정하고 (와 함께 실행 가능하게 함 chmod 755)


답변

execLinux 커널 의 시스템 호출은 #!기본적으로 shebang을 이해합니다 ( )

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 파일을 가져 와서 메모리에 올바르게 넣고 새 프로세스를 시작합니다. 또한 커널은 리눅스에서 실행 가능한 실행 바이너리 파일을 어떻게 얻습니까?

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

POSIX가 shebang을 지정 하지는 않는다고 생각 합니다 : https://unix.stackexchange.com/a/346214/32558 비록 이론적 근거 섹션과 시스템에서 실행 가능한 스크립트가 지원되는 경우 우연히 있다”. 그러나 macOS와 FreeBSD도 그것을 구현하는 것 같습니다.

PATH 검색 동기

아마도 shebang의 존재에 대한 큰 동기는 Linux에서 종종 PATH다음과 같이 명령을 실행하려고한다는 사실입니다 .

basename-of-command

대신에:

/full/path/to/basename-of-command

그러나 shebang 메커니즘이 없으면 Linux가 각 유형의 파일을 실행하는 방법을 어떻게 알 수 있습니까?

명령에서 확장자를 하드 코딩하십시오.

 basename-of-command.py

또는 모든 인터프리터에서 PATH 검색을 구현하십시오.

python basename-of-command

가능성이 있지만, 명령을 다른 언어로 리팩토링하기로 결정하면 모든 것이 깨지는 주요 문제가 있습니다.

Shebangs는이 문제를 아름답게 해결합니다.


답변

기술적으로 파이썬에서 이것은 주석 줄입니다.

이 행은 쉘에서 (명령 행에서) py 스크립트를 실행하는 경우에만 사용됩니다 . 이것은 세방 “으로 알려져 있습니다 . 파이썬 스크립트뿐만 아니라 다양한 상황에서 사용됩니다.

여기서는 쉘 이 파일의 나머지 부분을 처리하기 위해 특정 버전 의 Python 을 시작하도록 지시 합니다.