outer.sh
:
ls -l /proc/$$/exe
coproc cat
./inner.sh
kill $!
inner.sh
:
ls -l /proc/$$/exe
set | grep COPROC || echo No match found
coproc cat
kill $!
을 실행하면 ./outer.sh
다음이 인쇄됩니다.
lrwxrwxrwx 1 joe joe 0 Jun 16 22:47 /proc/147876/exe -> /bin/bash
lrwxrwxrwx 1 joe joe 0 Jun 16 22:47 /proc/147879/exe -> /bin/bash
No match found
./inner.sh: line 3: warning: execute_coproc: coproc [147878:COPROC] still exists
COPROC
자식에는 및 가 설정되어 있지 않으므로 COPROC_PID
부모의 자식이 나에게 이 경고를 줄 수 있는지 어떻게 알 수 있습니까?
#!/bin/bash
또한 의 맨 위에 추가하거나 from 대신 inner.sh
호출하면 경고가 사라지는 것을 발견했습니다. bash 하위 프로세스를 통해 실행되는데 왜 이것이 변경됩니까?bash ./inner.sh
./inner.sh
outer.sh
답변1
shebang이 없는 스크립트는 POSIX 호환 인터프리터로 해석됩니다 sh
. 이것은 실제로 POSIX 스크립트를 작성하는 POSIX 방식입니다. POSIX는 shebang을 지정하지 않습니다. 하지만 실제로 shebang을 사용하는 것이 더 이식 가능하고 안정적입니다. 여기에 좋은 예가 있습니다.
bash 쉘은 POSIX sh 인터프리터입니다. bash(일부 버전, 일부 사용자 정의 빌드 및 일부 환경)는 실제로 제가 아는 유일한 FLOSS 셸입니다.인증됨런타임이 규정을 준수합니다 sh
(런타임 아님 bash
).
shebang 없이 스크립트를 실행할 때 bash는 execve()
ENOEXEC를 반환하고 바이너리처럼 보이지 않는지 확인한 후 이를 하위 파일에서 해석하고 상태를 기본값으로 재설정하여 실행을 시뮬레이션합니다.
그러나 이는 스크립트 자체가 POSIX 모드에서 실행되지 않는 한(예: 자체로 호출되는 경우) run 시 스크립트가 bash
POSIX sh 스크립트가 아닌 bash 스크립트로 해석됨을 의미합니다.bash
sh
$ cat a
alias uname='echo hi'
uname
$ zsh -c ./a
hi
$ sh ./a
hi
$ bash -c ./a
Linux
$ (exec -a sh bash -c ./a)
hi
호출 시 a
sh 언어 대신 언어(별칭 무시)로 해석되는 방식을 이해합니다.bash
bash
~$ strace -qqfe execve bash -c ./a
execve("/usr/bin/bash", ["bash", "-c", "./a"], 0x7fff0081a820 /* 66 vars */) = 0
execve("./a", ["./a"], 0x55b18b3a4660 /* 66 vars */) = -1 ENOEXEC (Exec format error)
[pid 123559] execve("/usr/bin/uname", ["uname"], 0x55b18b3a4660 /* 66 vars */) = 0
Linux
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=123559, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
해석 스크립트를 bash
실행하지 않는 방법을 참조하세요 .sh
당신이 얻는 사실 warning: execute_coproc: coproc [147878:COPROC] still exists
은 버그이며 bash
그 상태를 제대로 재설정할 수 없습니다.
어쨌든 coproc
이는 키워드가 아니므 sh
로 shebang-less 스크립트에서는 자리를 차지하지 않습니다. 구현은 완전히 다르지만 (그리고 보조 프로세스는 ksh에서 옵니다) coproc
여기 에 셔뱅이 있어야 합니다.zsh
bash
#! /bin/bash -
shebang을 사용 bash ./inner.sh
하거나 사용하면 새 인터프리터 인스턴스가 올바르게 실행되고 execve()
프로세스 메모리가 완전히 올바르게 지워집니다.