Насколько я понял из онлайн-документации, следующая команда должна создать подоболочку для части команды, встроенной в {}
:
$ bash -c '{ sleep 10; echo "Sleeping process", $$; } & echo $$; '
11237
Sleeping process, 11237
Однако, как вы видите, в обоих случаях идентификатор процесса один и тот же. Что я упускаю? Спасибо за любые указания.
решение1
Команда {}
just группирует команды в текущей оболочке, в то время как ()
запускает новую подоболочку. Однако то, что вы делаете, это помещает сгруппированные команды в фоновый режим, который действительно является новым процессом; если бы он был в текущем процессе, он, возможно, не мог бы быть переведен в фоновый режим. Проще, 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 означает, что он также следует за дочерними процессами, показывая еще один fork (ну, "клон"), когда он запускает sleep. Если вы не включите -f, вы увидите только один вызов clone, когда он создает фоновый процесс:
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) = ?
Если вы действительно просто хотите узнать, как часто вы создаете новые процессы, вы можете упростить это еще больше, отслеживая только вызовы fork и clone:
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
решение2
Обновлять:
Пожалуйста, смотрите ответ выше. С помощью {} я на самом деле не создаю подоболочку. Вместо этого, фоновое заземление здесь дает мне ответ, который я искал.
Ладно, в общем-то, я использовал неверный "индикатор" создаваемых подоболочек. Я узнал о том, что BASHPID
изздесьи используя это в дополнение к BASH_SUBSHELL
, я могу видеть, что подоболочка действительно создается.
Тестовая команда:
$ bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; } & echo $BASHPID; '
12074
Sleeping process, 12075, 1
Еще одна тестовая команда, также отображающая идентификатор родительского процесса как для оболочки, так и для подоболочки:
$ bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL, $PPID; } & echo $BASHPID, $PPID; '
12411, 9128
$ Sleeping process, 12412, 1, 9128