왜 경로가없는 세방을 사용하지 않습니까? $ PATH를 통해 찾을 수

인터프리터에 대한 경로를 지정하는 대신 인터프리터의 이름을 가지며 쉘이 $ PATH를 통해 찾을 수 있도록하는 shebang을 가질 수 있습니까?

그렇지 않다면 이유가 있습니까?



답변

PATH 조회는 일반적인 환경 변수와 마찬가지로 사용자 공간에서 표준 C 라이브러리의 기능입니다. 커널은 호출자 execve에서 새로운 프로세스로 환경을 넘길 때를 제외하고는 환경 변수를 보지 못합니다 .

커널은 경로 execve( execvpPATH 조회 수행 과 같은 랩퍼 기능에 달려 있음 ) 또는 shebang ( execve호출을 내부적으로 다소 라우팅하는 경로)에 대한 해석을 수행하지 않습니다 . 따라서 shebang¹에 절대 경로를 넣어야합니다. 원래 오두막 구현은 단지 몇 줄의 코드이며, 그것은 크게 이후 확장되지 않았습니다.

유닉스의 첫 번째 버전에서, 쉘은 스크립트를 호출하고 있음을 알았을 때 자체 호출 작업을 수행했습니다. Shebang은 몇 가지 이유로 커널에 추가되었습니다 ( Dennis Ritchie이론적 근거 요약 :

  • 호출자는 실행할 프로그램이 쉘 스크립트인지 원시 바이너리인지 걱정할 필요가 없습니다.
  • 스크립트 자체는 호출자 대신 사용할 인터프리터를 지정합니다.
  • 커널은 로그에서 스크립트 이름을 사용합니다.

경로없는 shebang은 환경 변수 및 프로세스에 액세스하기 위해 커널을 보강하거나 커널 PATH이 PATH 조회를 수행하는 사용자 공간 프로그램을 실행하도록해야합니다. 첫 번째 방법은 커널에 과도한 양의 복잡성을 추가해야합니다. 두 번째 방법은 이미 #!/usr/bin/envshebang으로 가능합니다 .

¹ 상대 경로를 설정하면 프로세스의 현재 디렉토리 (스크립트가 포함 된 디렉토리가 아님)로 상대적으로 해석되므로 shebang에서 거의 유용하지 않습니다.


답변

눈을 맞추는 것보다 더 많은 일이 있습니다. #!행은 유닉스 또는 리눅스 커널에 의해 해석되며 #!쉘의 측면이 아닙니다. 이것은 PATH커널이 무엇을 실행할지 결정할 때 실제로 존재하지 않음을 의미합니다 .

실행할 실행 파일을 모르거나 perl이식 가능한 방식 으로 호출하는 방법을 모르는 가장 일반적인 방법 은을 사용하는 것 #!/usr/bin/env perl입니다. 커널은 환경 변수 /usr/bin/env를 상속하는를 실행 PATH합니다. env(이 예에서) 발견 perlPATH와 사용하는 execve(2)시스템 호출은 실행 커널 얻기 위해 perl실행.


답변

$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0

전체 경로로의 변환은 쉘에 의해 수행됩니다 (일반적으로 사용자 공간에서). 커널은 직접 액세스 할 수있는 파일 이름 / 경로를 예상합니다.

PATH 변수를 통해 시스템이 실행 파일을 찾도록하려면 shebang을로 다시 작성할 수 있습니다 #!/usr/bin/env EXEC.

그러나이 경우 검색을 수행하는 것은 커널이 아닙니다.