web-dev-qa-db-ja.com

Bashとサブシェル

オンラインドキュメントから収集したものから、以下は{}で埋め込まれたコマンドの一部のサブシェルを生成するはずです。

$ bash -c '{ sleep 10; echo "Sleeping process", $$; }  & echo $$; '
11237
 Sleeping process, 11237

ただし、ご覧のとおり、どちらの場合もプロセスIDは同じです。何が足りないのですか?ポインタをありがとう。

5
Amit

_{}_は、現在のシェルでコマンドをグループ化するだけですが、_()_は新しいサブシェルを開始します。ただし、実行しているのは、グループ化されたコマンドをバックグラウンドに配置することです。これは、実際には新しいプロセスです。現在のプロセスにある場合は、バックグラウンドで実行できない可能性があります。 IMHO、straceでこの種のものを見るのは簡単です:

_sauer@humpy:~$ strace -f -etrace=process bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /tmp/file
execve("/bin/bash", ["bash", "-c", "{ sleep 10; echo \"Sleeping proce"...], [/* 20 vars */]) = 0
Arch_prctl(Arch_SET_FS, 0x7f15a90da700) = 0
clone(Process 25347 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f15a90da9d0) = 25347
[pid 25346] exit_group(0)               = ?
clone(Process 25348 attached (waiting for parent)
Process 25348 resumed (parent 25347 ready)
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f15a90da9d0) = 25348
[pid 25348] execve("/bin/sleep", ["sleep", "10"], [/* 20 vars */] <unfinished ...>
[pid 25347] wait4(-1, Process 25347 suspended
 <unfinished ...>
[pid 25348] <... execve resumed> )      = 0
[pid 25348] Arch_prctl(Arch_SET_FS, 0x7f922ad16700) = 0
[pid 25348] exit_group(0)               = ?
Process 25347 resumed
Process 25348 detached
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 25348
--- SIGCHLD (Child exited) @ 0 (0) ---
wait4(-1, 0x7fffaa432ad8, WNOHANG, NULL) = -1 ECHILD (No child processes)
exit_group(0)                           = ?
Process 25347 detached

sauer@humpy:~$ cat /tmp/file
25346
Sleeping process, 25347, 1
_

Bashコマンドが開始され、clone()で新しい子が作成されることに注意してください。 -fオプションをstraceに使用すると、子プロセスも追跡され、スリープを実行するとさらに別のフォーク(「クローン」)が表示されます。 -fをオフのままにすると、バックグラウンドプロセスを作成するときに、クローン呼び出しが1つだけ表示されます。

_sauer@humpy:~$ strace -etrace=clone bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /tmp/file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f2bdd5399d0) = 26394
sauer@humpy:~$ strace -etrace=process bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /dev/null
execve("/bin/bash", ["bash", "-c", "{ sleep 10; echo \"Sleeping proce"...], [/* 20 vars */]) = 0
Arch_prctl(Arch_SET_FS, 0x7fd01ae86700) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fd01ae869d0) = 26706
exit_group(0)                           = ?
_

新しいプロセスを作成する頻度を本当に知りたい場合は、フォークとクローンの呼び出しを監視するだけで、それをさらに単純化できます。

_sauer@humpy:~$ strace -etrace=fork,clone bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /dev/null
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f467fa769d0) = 27025
_
7
dannysauer

更新:

上記の回答をご覧ください。 {}では、実際にはサブシェルを作成していません。代わりに、ここでのバックグラウンドは私が探していた答えを私に与えます。

さて、基本的に私は作成されているサブシェルの誤った「インジケータ」を使用していました。 here からBASHPIDについて学び、BASH_SUBSHELLに加えてそれを使用すると、サブシェルが実際に作成されていることがわかります。

テストコマンド:

$ bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID; '
12074
 Sleeping process, 12075, 1

シェルとサブシェルの両方の親プロセスIDも表示する別のテストコマンド:

$ bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL, $PPID; }  & echo $BASHPID, $PPID; '
12411, 9128
$ Sleeping process, 12412, 1, 9128
5
Amit