如何获取子shell的pid?

Tim*_*Tim 17 bash process subshell

如何获取子shell的pid?

例如:

$ echo $$
16808
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为原始外壳扩展$$

$ ( echo $$ )
16808
Run Code Online (Sandbox Code Playgroud)

为什么单引号不起作用?原shell去掉单引号后,子shell$$自己不展开了吗?

$ ( echo '$$' )
$$
Run Code Online (Sandbox Code Playgroud)

为什么也eval不起作用?是eval由子shell 运行的吗?为什么它会给我原始外壳的 PID?

$ ( eval echo '$$' )
16808
Run Code Online (Sandbox Code Playgroud)

谢谢。

Kus*_*nda 20

$ echo $BASHPID
37152
$ ( echo $BASHPID )
18633
Run Code Online (Sandbox Code Playgroud)

从手册:

BASHPID

扩展到当前 bash 进程的进程 ID。这与$$某些情况下不同,例如不需要重新初始化 bash 的子 shell。

$

扩展到 shell 的进程 ID。在()子shell中,它扩展到当前shell的进程ID,而不是子shell。

有关的:

  • @Tim 无法可靠地找到子外壳的父外壳的 PID,除非您安排将 `$BASHPID` 保存在变量中并在子外壳中使用它。有`$PPID`,但它是shell 的父PID,与`$$` 是shell 的PID 相同(它不会在子shell 中重置)。没有`$bashppid` 变量。 (2认同)

mos*_*svy 13

除了bash's $BASHPID,您还可以通过以下方式轻松实现:

pid=$(exec sh -c 'echo "$PPID"')
Run Code Online (Sandbox Code Playgroud)

例子:

(pid=$(exec sh -c 'echo "$PPID"'); echo "$$ $pid")
Run Code Online (Sandbox Code Playgroud)

你可以把它变成一个函数:

# usage getpid [varname]
getpid(){
    pid=$(exec sh -c 'echo "$PPID"')
    test "$1" && eval "$1=\$pid"
}
Run Code Online (Sandbox Code Playgroud)

请注意,某些外壳程序(例如zshksh93)不会为每个使用(...);创建的子外壳程序启动子进程。在这种情况下,$pid可能最终与 相同$$,这是正确的,因为这getpid是调用进程的 PID 。

  • 不会。但请不要假设子 shell 必须在子进程中运行——例如,“ksh93”中的情况并非如此。 (2认同)
  • 它在 ksh93 中工作得很好——它总是返回调用它的进程的 pid。示例中的“(...)”可能不会像“bash”中那样生成单独的进程。 (2认同)
  • 此外,某些 shell(如“zsh”或“yash”)优化了子 shell 中最后一个命令的“fork()”。如果它是脚本中的最后一个命令,他们甚至可能优化子 shell 的 fork,这样你的“getpid”甚至可以报告“$$”的父级。您可以将 `getpid` 定义为: `getpid(){ sh -c 'echo "$PPID"'; 返回; }` 禁用以避免该问题。 (2认同)
  • @HaroldFischer 1.如果没有“exec”或没有该优化,“sh -c ...”进程将是孙子进程,而不是使用“$(...)”命令替换的进程的子进程,而 `$PPID` 将是 `$(...)` 子 shell 的 pid。这正是上面 `set -E` + `trap ERR` bash 示例中发生的情况。 (2认同)