인터프리터에 대한 경로를 지정하는 대신 인터프리터의 이름을 가지며 쉘이 $ PATH를 통해 찾을 수 있도록하는 shebang을 가질 수 있습니까?
그렇지 않다면 이유가 있습니까?
인터프리터에 대한 경로를 지정하는 대신 인터프리터의 이름을 가지며 쉘이 $ PATH를 통해 찾을 수 있도록하는 shebang을 가질 수 있습니까?
그렇지 않다면 이유가 있습니까?
답변:
PATH 조회는 일반적인 환경 변수와 마찬가지로 사용자 공간에서 표준 C 라이브러리의 기능입니다. 커널은 호출자 execve
에서 새로운 프로세스로 환경을 넘길 때를 제외하고는 환경 변수를 보지 못합니다 .
커널은 경로 execve
( execvp
PATH 조회 수행 과 같은 랩퍼 기능에 달려 있음 ) 또는 shebang ( execve
호출을 내부적으로 다소 라우팅하는 경로)에 대한 해석을 수행하지 않습니다 . 따라서 shebang¹에 절대 경로를 넣어야합니다. 원래 오두막 구현은 단지 몇 줄의 코드이며, 그것은 크게 이후 확장되지 않았습니다.
유닉스의 첫 번째 버전에서, 쉘은 스크립트를 호출하고 있음을 알았을 때 자체 호출 작업을 수행했습니다. Shebang은 몇 가지 이유로 커널에 추가되었습니다 ( Dennis Ritchie 의 이론적 근거 요약 :
경로없는 shebang은 환경 변수 및 프로세스에 액세스하기 위해 커널을 보강하거나 커널 PATH
이 PATH 조회를 수행하는 사용자 공간 프로그램을 실행하도록해야합니다. 첫 번째 방법은 커널에 과도한 양의 복잡성을 추가해야합니다. 두 번째 방법은 이미 #!/usr/bin/env
shebang으로 가능합니다 .
¹ 상대 경로를 설정하면 프로세스의 현재 디렉토리 (스크립트가 포함 된 디렉토리가 아님)로 상대적으로 해석되므로 shebang에서 거의 유용하지 않습니다.
execve
shebang에 상대 경로를 갖는 것이 의미가 없지만 shebang에 절대 경로를 요구하지 않습니다 .
/lib64/ld-linux-x86-64.so.2
( ldd
출력 참조 ). 리눅스는 그것을 완전히 일반화시킨다 : binfmt
2.1.43 이후 지원은 인터프리터 경로 / 매직 넘버 또는 파일 확장자 쌍을 등록하게한다. PE32 를 실행할 때, Java 클래스 및 jar 파일을 .exe
호출 wine
할 때 등을 호출 할 수 있습니다 java
.
눈을 맞추는 것보다 더 많은 일이 있습니다. #!
행은 유닉스 또는 리눅스 커널에 의해 해석되며 #!
쉘의 측면이 아닙니다. 이것은 PATH
커널이 무엇을 실행할지 결정할 때 실제로 존재하지 않음을 의미합니다 .
실행할 실행 파일을 모르거나 perl
이식 가능한 방식 으로 호출하는 방법을 모르는 가장 일반적인 방법 은을 사용하는 것 #!/usr/bin/env perl
입니다. 커널은 환경 변수 /usr/bin/env
를 상속하는를 실행 PATH
합니다. env
(이 예에서) 발견 perl
에 PATH
와 사용하는 execve(2)
시스템 호출은 실행 커널 얻기 위해 perl
실행.
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0
전체 경로로의 변환은 쉘에 의해 수행됩니다 (일반적으로 사용자 공간에서). 커널은 직접 액세스 할 수있는 파일 이름 / 경로를 예상합니다.
PATH 변수를 통해 시스템이 실행 파일을 찾도록하려면 shebang을로 다시 작성할 수 있습니다 #!/usr/bin/env EXEC
.
그러나이 경우 검색을 수행하는 것은 커널이 아닙니다.
strace
로 실행 중입니다 ( /usr/bin/strace
어느 시점에서 변환됩니다 ).