AvidSeeker Asked: 2024-03-14 09:41:20 +0800 CST2024-03-14 09:41:20 +0800 CST 2024-03-14 09:41:20 +0800 CST 空子shell的shell检测 772 SC1143建议将包装 shell 命令的注释部分包装在子 shell 中。 Posix shell 是否“足够智能”,在发现子 shell 不执行任何操作时不会启动子 shell?Bash 和 Zsh 怎么样? shell 1 个回答 Voted Best Answer Stephen Kitt 2024-03-15T05:46:18+08:002024-03-15T05:46:18+08:00 正如ilkkachu 所写,POSIX 本身指定: shell 应通过在子 shell 环境中执行命令(请参阅Shell 执行环境)并用命令的标准输出替换命令替换(命令文本加上引号"$()"或反引号)来扩展命令替换,删除一个或多个序列替换末尾的 <newline> 字符。 然而,观察 shell 的实际行为会发现一些令人惊讶的事情(好吧,一个)。我使用的脚本仅包含 echo \ Before \ `# commented` \ After Bash 和 Zsh 分叉一个子 shell 来运行“空”命令替换: $ 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 +++ 另一方面,DASH解析反引号内的内容,以确定它们是否代表内置命令或外部命令,如果解析结果为空“节点”(空命令),则完全跳过它: $ strace -f -e process dash bttest execve("/bin/dash", ["dash", "bttest"], 0x7ffe61eee5c0 /* 67 vars */) = 0 Before After exit_group(0) = ? +++ exited with 0 +++ 因此,至少有一个 shell 足够“智能”,在这种情况下不会启动子 shell。 (不存在“POSIX shell”——POSIX 是一种规范,没有参考实现。据我所知,没有任何 shell 严格实现 POSIX,并且仅实现 POSIX。)
正如ilkkachu 所写,POSIX 本身指定:
然而,观察 shell 的实际行为会发现一些令人惊讶的事情(好吧,一个)。我使用的脚本仅包含
Bash 和 Zsh 分叉一个子 shell 来运行“空”命令替换:
另一方面,DASH解析反引号内的内容,以确定它们是否代表内置命令或外部命令,如果解析结果为空“节点”(空命令),则完全跳过它:
因此,至少有一个 shell 足够“智能”,在这种情况下不会启动子 shell。
(不存在“POSIX shell”——POSIX 是一种规范,没有参考实现。据我所知,没有任何 shell 严格实现 POSIX,并且仅实现 POSIX。)