SC1143래핑된 쉘 명령의 주석 부분을 서브쉘로 래핑하는 것이 좋습니다.
Posix 셸은 아무 작업도 수행하지 않는 경우 하위 셸을 시작하지 않을 만큼 "충분히 똑똑"합니까? Bash와 Zsh는 어떻습니까?
답변1
쉘은 서브쉘 환경에서 명령을 실행하여 명령 대체를 확장해야 합니다(참조:쉘 실행 환경) 및 명령 대체(텍스트)를 대체합니다.주문하다동봉되거나
"$()"
백틱 처리됨)을 명령의 표준 출력으로 대체하고 교체 끝에서 하나 이상의 <newline> 문자 시퀀스를 제거합니다.
그러나 쉘의 실제 동작을 관찰하면 몇 가지 놀라운 사실이 드러납니다(글쎄, 하나). 내가 사용하는 스크립트에는 다음이 포함되어 있습니다.
echo \
Before \
`# commented` \
After
Bash와 Zsh는 주석 전용 명령 대체를 실행하기 위해 하위 쉘을 포크합니다.
$ strace -f -e process bash bttest
execve("/bin/bash", ["bash", "bttest"], 0x7ffe31522a10 /* 67 vars */) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLDstrace: Process 3134851 attached
, child_tidptr=0x7fe3ef0c6a10) = 3134851
[pid 3134851] exit_group(0) = ?
[pid 3134851] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3134851, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG, NULL) = 3134851
wait4(-1, 0x7ffecdd13810, WNOHANG, NULL) = -1 ECHILD (No child processes)
Before After
exit_group(0) = ?
+++ exited with 0 +++
$ strace -f -e process zsh bttest
execve("/usr/bin/zsh", ["zsh", "bttest"], 0x7fffa2f78140 /* 67 vars */) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLDstrace: Process 3134903 attached
, child_tidptr=0x7f236ce63750) = 3134903
[pid 3134903] exit_group(0) = ?
[pid 3134902] kill(3134903, 0) = 0
[pid 3134903] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3134903, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, {ru_utime={tv_sec=0, tv_usec=593}, ru_stime={tv_sec=0, tv_usec=0}, ...}) = 3134903
wait4(-1, 0x7ffcabc4a7d4, WNOHANG|WSTOPPED|WCONTINUED, 0x7ffcabc4a7f0) = -1 ECHILD (No child processes)
kill(3134903, 0) = -1 ESRCH (No such process)
Before After
exit_group(0) = ?
+++ exited with 0 +++
스프린트반면, 역따옴표 안에 있는 내용은 구문 분석되어 내장 명령을 나타내는지 외부 명령을 나타내는지 결정하고, 구문 분석 결과 빈 "노드"(빈 명령)가 생성되면,완전히 건너뛰세요:
$ strace -f -e process dash bttest
execve("/bin/dash", ["dash", "bttest"], 0x7ffe61eee5c0 /* 67 vars */) = 0
Before After
exit_group(0) = ?
+++ exited with 0 +++
Bash 및 Zsh와 마찬가지로 명령이 백틱으로 묶인 경우 DASH가 분기됩니다.
echo \
Before \
`: # commented` \
After
우리는 얻었다
$ strace -f -e process dash bttest
execve("/bin/dash", ["dash", "bttest"], 0x7fff762e6260 /* 41 vars */) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7effab920850) = 3905359
strace: Process 3905359 attached
[pid 3905359] exit_group(0) = ?
[pid 3905359] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3905359, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 3905359
wait4(-1, 0x7ffdb1e8683c, WNOHANG, NULL) = -1 ECHILD (No child processes)
Before After
exit_group(0) = ?
+++ exited with 0 +++
따라서 최소한 하나의 쉘은 이 경우 서브쉘을 시작하지 않을 만큼 충분히 "지능적"입니다.
:
ksh93과 같은 일부 셸은 테스트된 변형 에서도 strace
알 수 있듯이 외부 명령을 포함하지 않는 하위 셸을 포크하지 않습니다.
$ strace -f -e process ksh93 bttest
execve("/bin/ksh93", ["ksh93", "bttest"], 0x7ffce3c73510 /* 41 vars */) = 0
Before After
exit_group(0) = ?
+++ exited with 0 +++
("POSIX 쉘"은 없습니다. POSIX는 참조 구현이 아니라 사양입니다. 내가 아는 한 POSIX를 엄격하게 구현하는 쉘은 없으며 오직 POSIX만 구현합니다.)