【问题标题】:How to get the process id of a bash subprocess on command line如何在命令行上获取 bash 子进程的进程 ID
【发布时间】:2012-02-25 13:17:01
【问题描述】:

我知道在 bash 中我们可以使用圆括号 () 创建子shell。根据 bash 手册页:

(list) list  is  executed  in  a  subshell environment 

还要获取我们使用的当前进程ID

echo $$

现在我的问题是如何获取在命令行上使用() 创建的子shell 的进程ID?

如果我使用这个:

echo $$; ( echo $$; ) 

我将在标准输出上打印两次父 shell 的进程 ID,因为 $$ 甚至在创建子 shell 之前就已扩展。那么如何真正强制惰性扩展呢?

[解决方案不仅适用于 Linux,还应该适用于 Mac]

更新:

建议的链接答案不起作用,因为 echo $BASHPID 不起作用在我的 Mac 上并返回空白。

【问题讨论】:

  • 我相信 BASHPID 需要 Bash 4,而 OS X 附带 Bash 3.2
  • @anubhava:没错,但我们(SO 社区)直到你编辑才知道这一点;-)
  • 是的,但在另一个问题中没有迹象表明那里提供的解决方案不适用于 Mac。这是使这不是重复的关键点。
  • 有趣的是,$$ 在子shell 中不起作用的原因与您在问题中所指出的不完全一样。如果问题只是在执行 subshel​​l 代码之前 $$ 正在扩展,您可以通过执行 (eval echo '$$') 轻松解决此问题,但实际上,这也不起作用。根据tldp.org/LDP/abs/html/internalvariables.html 的最后一个脚注,$$ 只返回顶层的pid,句点。但是,它没有说明原因。我不知道这个问题的答案。
  • 请注意,如果您只想获得一个简单且可用的子进程 PID(不是括号内的一个):serverfault.com/questions/205498/…

标签: macos bash shell unix process


【解决方案1】:

感谢大家花费宝贵的时间在这里寻找我的问题的答案。

但是我现在正在回答我自己的问题,因为我找到了一种 hack 方法来在 bash ver

echo $$; ( F='/tmp/myps'; [ ! -f $F ] && echo 'echo $PPID' > $F; )

打印出来:

5642
13715

其中 13715 是 subshel​​l 的 pid。在我这样做时进行测试:

echo $$; ( F='/tmp/myps'; [ ! -f $F ] && echo 'echo $PPID' > $F; bash $F; ps; )

我明白了:

5642
13773
  PID   TT  STAT      TIME COMMAND
 5642 s001  S      0:02.07 -bash
13773 s001  S+     0:00.00 -bash

告诉我 13773 确实是 subshel​​l 的 pid。

注意:因为@ChrisDodd 评论说echo $$; ( bash -c 'echo $PPID'; ) 不适用于Linux,所以我恢复了原来的解决方案。我的上述解决方案适用于 Mac 和 Linux。

【讨论】:

  • sh -c 'echo $PPID' 是一种更短的方法
  • 一个奇怪的地方:当我在我的计算机 (Linux) 上运行 echo $$; ( bash -c 'echo $PPID'; ) 时,它会打印两次相同的 pid...
  • @ChrisDodd 命令组没有在子shell 中运行,因为它的命令列表只包含一个命令(这是一个未记录的优化)。使用echo $$; (:; bash -c 'echo $PPID') 强制使用子shell。
  • @ChrisDodd 如果您从 shell 尝试过,那么它可以按预期工作。试试这个以查看不同的值:( echo $$; ( sh -c 'echo $PPID'; ) ) 它适用于我在 ubuntu 12.04 和 OSX 10.9.2 下
  • 就我个人而言,这对我有用echo $$; (echo 'echo $PPID' | bash) 只是上述的另一种变体。
【解决方案2】:

不幸的是,在引入 $BASHPID 的 bash 版本 4 之前,没有简单的方法可以做到这一点。您可以做的一件事是编写一个打印其父 PID 的小程序:

int main()
{
    printf("%d\n", getppid());
    return 0;
}

如果你把它编译为ppid 并将它放在你的路径中,你可以调用它,例如:

$ (echo $$; ppid)
2139
29519
$ (x=$(ppid); echo $x)
29521

然而,我注意到一个奇怪的地方是,如果你写

$ (ppid)

它似乎并没有真正在子shell中运行——您需要在括号内至少有两个命令才能让bash在子shell中实际运行它们。

【讨论】:

    【解决方案3】:

    你可以这样做:

    $ ( your_action ) &
    [1] 44012
    

    然后像这样找到子进程的 PID:

    $ echo "The sub PID : $!"
    The Sub PID : 44012
    

    $! 返回后台 PID 中的最后一个作业。 (见this manual

    【讨论】:

    • 很好的尝试,但它只在下一个命令和子外壳之外获取子进程的 ID。
    【解决方案4】:

    在 Mac 上使用 homebrew 安装 pgrep:brew install pgrep

    查看http://mxcl.github.com/homebrew/ 以安装 Homebrew。

    【讨论】:

    • 很抱歉作为原始无关问题的答案发布,但我无法对上一篇文章发表评论。
    【解决方案5】:

    这似乎可行:

    (echo $$; echo  `ps axo pid,command,args | grep "$$" |awk '{ getline;print $1}'`)
    14609
    17365
    

    无论出于何种原因,OSX 都受到限制并且没有 pgrep,或者可以这样做(在 Linux 中有效):

     (echo $$; echo  `pgrep -P $$`) 
     14609
     17390
    

    【讨论】:

    • 不是真的,这将打印 sub+sub+sub+sub shell 的 pid,因为 ( 和 ) 内部有 3 个管道。
    • 阿努巴瓦你能看看这个问题。这对你来说应该很容易。这是链接:stackoverflow.com/questions/31961615/…
    【解决方案6】:

    您可以通过在首次进入 shell 时回显父级的 BASHPID 来使用父级的 ppid,然后将进程置于后台并可以使用父级通过 ppid 查找 pid pid

    例如要在子 shell 中获取 sleep 555 命令的 pid:

    (echo "$BASHPID" > /tmp/_tmp_pid_ && sleep 555 &) && ps -ho pid --ppid=$(< /tmp/_tmp_pid_)

    【讨论】:

      猜你喜欢
      • 2014-02-27
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多