이 스크립트를 실행할 때 죽을 때까지 실행되도록 …
# foo.sh
while true; do sleep 1; done
… 다음을 사용하여 찾을 수 없습니다 ps ax
.
>./foo.sh
// In a separate shell:
>ps ax | grep foo.sh
21110 pts/3 S+ 0:00 grep --color=auto foo.sh
…하지만 일반적인 ” #!
“헤더를 스크립트에 추가하면 …
#! /usr/bin/bash
# foo.sh
while true; do sleep 1; done
… 그리고 같은 ps
명령으로 스크립트를 찾을 수있게됩니다 …
>./foo.sh
// In a separate shell:
>ps ax | grep foo.sh
21319 pts/43 S+ 0:00 /usr/bin/bash ./foo.sh
21324 pts/3 S+ 0:00 grep --color=auto foo.sh
왜 그렇습니까?
이것은 관련 질문 일 수 있습니다. ” #
“은 (는) 주석 접두사 일 뿐이라고 생각 하면 ” #! /usr/bin/bash
“자체는 주석에 지나지 않습니다. 그러나 ” #!
“은 단순한 의견보다 더 큰 의미를 지니고 있습니까?
답변
현재 대화식 쉘이 bash
이고 #!
라인 없이 스크립트를 bash
실행하면 스크립트가 실행됩니다. 프로세스는 ps ax
출력에 그대로 표시됩니다 bash
.
$ cat foo.sh
# foo.sh
echo "$BASHPID"
while true; do sleep 1; done
$ ./foo.sh
55411
다른 터미널에서 :
$ ps -p 55411
PID TT STAT TIME COMMAND
55411 p2 SN+ 0:00.07 bash
관련 :
관련 섹션은 bash
매뉴얼을 구성합니다 .
파일이 실행 파일 형식이 아니고 파일이 디렉토리가 아니기 때문에이 실행이 실패하면 파일은 쉘 명령을 포함하는 파일 인 shell script로 간주됩니다 . 서브 쉘이 스폰 되어 실행됩니다. 이 서브 쉘은 자체적으로 다시 초기화되므로 , 부모가 기억하는 명령 위치 (SHELL BUILTIN COMMANDS 아래의 해시 참조)가 자식에 의해 유지되는 경우를 제외하고는 스크립트를 처리하기 위해 새 쉘이 호출 된 것처럼 효과가 나타 납니다.
프로그램이로 시작하는 파일
#!
인 경우 첫 번째 행의 나머지 부분은 프로그램의 인터프리터를 지정합니다. 쉘은 이 실행 파일 형식 자체를 처리하지 않는 운영 체제 에서 지정된 인터프리터 를 실행합니다. […]
즉 ./foo.sh
, 명령 줄에서 실행 하는 경우-줄 foo.sh
이없는 경우 #!
파일에서 명령을 하위 셸에서 실행하는 것과 같습니다.
$ ( echo "$BASHPID"; while true; do sleep 1; done )
으로 적절한 #!
예에 – 라인 포인팅 /bin/bash
, 그것은 일을 같이하다
$ /bin/bash foo.sh
답변
쉘 스크립트가로 시작 #!
하면 첫 번째 줄은 쉘에 관한 한 주석입니다. 그러나 처음 두 문자는 시스템의 다른 부분 인 커널에 의미가 있습니다. 두 문자 #!
는 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
답변
첫 번째 경우, 스크립트는 현재 쉘에서 분기 된 자식에 의해 실행됩니다.
먼저 실행 echo $$
한 다음 쉘의 프로세스 ID가 상위 프로세스 ID 인 쉘을 살펴 봐야합니다.