쉘 스크립트가로 시작 #!
하면 첫 번째 줄은 쉘에 관한 한 주석입니다. 그러나 처음 두 문자는 시스템의 다른 부분 인 커널에 의미가 있습니다. 두 문자 #!
는 shebang 이라고합니다 . shebang의 역할을 이해하려면 프로그램 실행 방법을 이해해야합니다.
파일에서 프로그램을 실행하려면 커널의 조치가 필요합니다. 이것은 execve
시스템 호출의 일부로 수행됩니다 . 커널은 파일 권한을 확인하고, 현재 호출 프로세스에서 실행중인 실행 파일과 관련된 리소스 (메모리 등)를 비우고, 새로운 실행 파일에 대한 리소스를 할당하고, 새로운 프로그램에 제어권을 전달해야합니다. 나는 언급하지 않을 것이다). execve
시스템 호출은 현재 실행중인 프로세스의 코드를 대체; fork
새로운 프로세스를 만들기 위해 별도의 시스템 호출 이 있습니다.
이를 위해 커널은 실행 파일의 형식을 지원해야합니다. 이 파일에는 커널이 이해하는 방식으로 구성된 머신 코드가 포함되어 있어야합니다. 쉘 스크립트에는 머신 코드가 포함되어 있지 않으므로 이런 방식으로 실행할 수 없습니다.
shebang 메커니즘을 통해 커널은 코드를 다른 프로그램으로 해석하는 작업을 연기 할 수 있습니다. 커널이 실행 파일이로 시작하는 #!
것을 발견하면 다음 몇 문자를 읽고 파일 의 첫 번째 줄 (선행 #!
및 선택적 공백 제외)을 다른 파일의 경로 (및 여기에서 설명하지 않는 인수)로 해석합니다 . ). 커널이 파일을 실행하라는 명령을 받았을 때 /my/script
파일이 행으로 시작하는 것을 알면 #!/some/interpreter
커널은 /some/interpreter
인수로 실행 합니다 /my/script
. 그런 다음 실행해야하는 스크립트 파일 /some/interpreter
을 결정 /my/script
해야합니다.
파일이 커널이 이해하는 형식의 원시 코드를 포함하지 않고 shebang으로 시작하지 않으면 어떻게 될까요? 그러면 파일이 실행 가능하지 않고 execve
시스템 호출이 오류 코드 ENOEXEC
(실행 파일 형식 오류) 와 함께 실패합니다 .
이것은 이야기의 끝일 수 있지만 대부분의 쉘은 대체 기능을 구현합니다. 커널이을 반환 ENOEXEC
하면, 셸은 파일의 내용을보고 셸 스크립트처럼 보이는지 확인합니다. 쉘이 파일이 쉘 스크립트처럼 보인다고 생각하면 자체적으로 실행합니다. 이를 수행하는 방법에 대한 세부 사항은 쉘에 따라 다릅니다. ps $$
스크립트 에 추가하여 어떤 일이 발생했는지 확인할 수 있으며 strace -p1234 -f -eprocess
, 1234가 쉘의 PID 인 프로세스를 보면 더 많은 것을 볼 수 있습니다 .
bash에서이 폴백 메커니즘은 호출 fork
하지만 호출 하지 않음 으로써 구현됩니다 execve
. 자식 bash 프로세스는 자체 내부 상태를 지우고 새 스크립트 파일을 열어 실행합니다. 따라서 스크립트를 실행하는 프로세스는 여전히 원래 bash 코드 이미지와 bash를 원래 호출했을 때 전달 된 원래 명령 행 인수를 사용합니다. ATT ksh는 같은 방식으로 동작합니다.
% bash --norc
bash-4.3$ ./foo.sh
PID TTY STAT TIME COMMAND
21913 pts/2 S+ 0:00 bash --norc
반대로 Dash 는 인수로 전달 된 스크립트의 경로를 ENOEXEC
호출 /bin/sh
하여 반응합니다 . 즉, 대시에서 shebangless 스크립트를 실행하면 스크립트에가있는 shebang 줄이있는 것처럼 동작 #!/bin/sh
합니다. Mksh와 zsh는 같은 방식으로 동작합니다.
% dash
$ ./foo.sh
PID TTY STAT TIME COMMAND
21427 pts/2 S+ 0:00 /bin/sh ./foo.sh