空のサブシェルのシェル検出

空のサブシェルのシェル検出

SC1143ラップされたシェルコマンドのコメント部分をサブシェルでラップすることをお勧めします。

Posixシェルは、何もしないとサブシェルを起動しないほど「十分にスマート」ですか? BashとZshはどうですか?

答え1

〜のようにイルカチョ 書くPOSIX自体が指定します

シェルはサブシェル環境でコマンドを実行してコマンド置換を拡張する必要があります(参照:シェル実行環境)とコマンドの置換(テキスト)を置き換えます。注文する同封または"$()"バックティック処理) をコマンドの標準出力に置き換え、置換の末尾から 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 +++

したがって、少なくとも1つのシェルはこの場合、サブシェルを起動しないほど十分に「インテリジェント」です。

: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のみを実装します。)

関連情報