bash
이라는 스크립트 가 있습니다 test.sh
. shebang을 사용 startproc
하면 파일 은 다음과 같습니다.#!/usr/bin/env bash
test.sh
/proc/<PID>/cmdline
SERVER:~ # cat /proc/29481/cmdline
bash/root/user/test.shSERVER:~ #
SERVER:~ #
#!/bin/bash
이제 Shebang 줄을 : 으로 변경하면 /proc/<PID>/cmdline
파일은 다음과 같습니다.
SERVER:~ # cat /proc/29729/cmdline
/bin/bash/root/user/test.shSERVER:~ #
SERVER:~ #
이 동작의 원인은 무엇입니까? 파일 내용이 /proc/<PID>/cmdline
스크립트 shebang에 따라 달라지나요? 문제는 이전 옵션을 사용하는 경우 checkproc
서비스 를 감지할 수 없다는 killproc
것 입니다 . 나는 openSUSE 11.4와 .startproc
test.sh
sysvinit-tools-2.88-37.47.1.x86_64
답변1
예, 수행된 시스템 호출 cmdline
에 따라 정규화된 경로는 경로 검색에 나타나는 경로와 다를 수 있습니다.exec*
env(1)
bash-4.1$ cat aaa
#!/bin/bash
xxd /proc/$$/cmdline
bash-4.1$ cat bbb
#!/usr/bin/env bash
xxd /proc/$$/cmdline
bash-4.1$ ./aaa
0000000: 2f62 696e 2f62 6173 6800 2e2f 6161 6100 /bin/bash../aaa.
bash-4.1$ ./bbb
0000000: 6261 7368 002e 2f62 6262 00 bash../bbb.
bash-4.1$
strace
세부정보 표시:
bash-4.1$ strace ./aaa 2>&1 | grep exec
execve("./aaa", ["./aaa"], [/* 57 vars */]) = 0
bash-4.1$ strace ./bbb 2>&1 | grep exec
execve("./bbb", ["./bbb"], [/* 57 vars */]) = 0
execve("/sbin/bash", ["bash", "./bbb"], [/* 57 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/sbin/bash", ["bash", "./bbb"], [/* 57 vars */]) = -1 ENOENT (No such file or directory)
execve("/usr/local/sbin/bash", ["bash", "./bbb"], [/* 57 vars */]) = -1 ENOENT (No such file or directory)
execve("/bin/bash", ["bash", "./bbb"], [/* 57 vars */]) = 0
bash-4.1$
Linux 전용 스크립트인 경우 위치는 변경되지 않을 수 있습니다(예외: , bash
다른 곳에 를 포함하는 bash
일종의 소프트웨어 라이브러리 가 있습니다). 따라서 정규화된 경로를 사용하는 것이 가장 적합할 것입니다. 이렇게 하면 env(1)
경로 검색 시 혼란을 피하고 init 도구와의 호환성을 얻을 수 있습니다.
답변2
프로세스의 명령줄은 argv
매개변수 요소로 구성됩니다.execve
시스템 호출. 이 매개변수는 0부터 시작하는 번호의 배열입니다. 여기서 1부터 n까지의 요소는 명령을 호출할 때 전달되는 매개변수이고, 요소 0은 호출 쉘이나 다른 프로그램에 의해 선택됩니다 execve
. 관례적으로 요소 0은 명령을 지정하는 문자열입니다.
Shebang 라인은 커널에 의해 처리됩니다. 커널은 #!
매직 접두사 뒤에 지정된 경로 인 매개변수 0을 삽입합니다 . 따라서 /root/user/test.sh
0=에서 하나의 인수로 실행하는 경우 1=에서는 두 개의 인수로 호출합니다. 로 시작할 때 커널은 shebang을 보고 인수 목록을 0= , 1= , 2= 로 다시 작성합니다.foo
startproc
startproc
execve
/root/user/test.sh
foo
/root/user/test.sh
/bin/bash
/root/user/test.sh
/bin/bash
/root/user/test.sh
foo
shebang 줄이 이면 #!/bin/env bash
커널은 인수 목록에 프로그램과 인수라는 두 항목을 삽입합니다. (Linux는 여기서 단일 인수로 제한됩니다.) 따라서 이 경우 호출은 0= /bin/env
, 1= bash
, 2= /root/user/test.sh
, 3= 으로 변환됩니다 foo
. 프로그램 env
은 작업을 완료하고 새로운 execve
시스템 호출 0= bash
(매개변수 0이 명령을 지정하는 데 사용되는 경로라는 규칙을 준수함), 1= /root/user/test.sh
, 2= 을 발행합니다 foo
.
모든 경우에 /root/user/test.sh
이는 프로시저에 대한 첫 번째 인수가 됩니다.