【问题标题】:Bash: Get child process nameBash:获取子进程名称
【发布时间】:2016-06-01 09:24:39
【问题描述】:

我是 bash 的新手。我有这个小代码:
bash.sh

./mama

ma​​ma.cpp

#include <stdlib.h>
int main()
{
  system("./shvili");
  while(1){}
}

shvili.cpp

int main()
{
  while(1){}
}

正如它向我展示的那样,mamashvili 进程的父进程。我有这样的情况,我不知道子进程的确切名称。所以我的问题是,如何从 c++ 中获取子进程的 PID?(获取进程名称对我来说会更舒服)。

【问题讨论】:

  • 为什么不用fork + exec 代替系统调用?

标签: c++ linux bash parent-child


【解决方案1】:

一种至少通过 bash 检查的方法,以防“像这样的情况,我不确切知道子进程的名称”但知道父进程的名称假定是唯一的,可以在 bash 中使用基于psgrepsed(为较小的 pid 删除前导空格)、tr(将多个连续的空格压缩为一个)和cut

$> cat foo_bar.sh 
#! /bin/bash
sleep 120

$> ./foo_bar.sh &
[1] 89239

$> ps -eo pid,ppid,args|grep -e " $(ps -eo pid,args| grep foo_bar.sh| grep -v grep| sed s/^\ //g |cut -f 1 -d ' ') "|grep -v foo_bar.sh| sed s/^\ //g | tr -s ' ' | cut -f 1,3 -d ' '
89241 sleep

因此使用父进程的唯一名称来确定父pid:

$> ps -eo pid,args| grep foo_bar.sh| grep -v grep| sed s/^\ //g |cut -f 1 -d ' '
89239

在子进程 ($(...)) 中评估的这个值用于从另一个 ps 调用中 grep 正确的行,以确定子进程和名称的搜索 pid(没有额外的参数并且事先不知道子进程的名字。

注意 - 在 bash 中,一些空格很重要 - 在搜索模式末尾添加的空格:

... grep " $(ps -eo pid,args| grep foo_bar.sh| grep -v grep| cut -f 1 -d ' ') " ...

这有助于避免误报,例如当父 pid 为 123 时,如果不使用空格填充,这将匹配许多包含这些数字的 pid,例如 1234、12345、1123、...

更新(对评论做出反应):如果父进程是a_mama(分叉a_shvili 子进程)并且它是机器上唯一具有该名称的进程,那么以下应该工作:

$> p_proc="a_mama"
$> ps -eo pid,ppid,args|grep -e " $(ps -eo pid,args| grep ${p_proc}| grep -v grep| sed s/^\ //g | cut -f 1 -d ' ') "|grep -v ${p_proc}| sed s/^\ //g | tr -s ' ' | cut -f 1,3 -d ' '
12346 a_shvili

【讨论】:

  • 我知道这不是 C++ 解决方案,但如前所述,在测试或无法访问源代码时可能会派上用场。
  • 在我将 sleep 120 更改为 mama ps -eo pid,ppid,args|grep -e " $(ps -eo pid,args| grep foo_bar.sh| grep -v grep| cut -f 1 -d ' ') "|grep -v foo_bar.sh| cut -f 1,3 -d ' ' 后,我得到了带有大量 PID 的输出
  • 哦,我明白了,但是foo_bar.sh 是您的mama 父进程 进程的模拟,因此sleep 120 将是子进程shvili 在你的问题中),所以你应该在后台启动mama(作为父级),或者然后在另一个终端中用mama替换我的食谱中的foo_bar.sh(希望它不会匹配太多正在运行的进程名称...
  • 这没有帮助。仍然有很多 PID。
  • 请再次尝试更新配方以防止 ps 添加的空格来填充较小的 pid。 PS:当没有找到匹配的父项时,grep 将空模式与 ps 结果匹配,从而给出所有条目 ...
【解决方案2】:

您可以尝试使用pidof 来获取特定进程的 pid。

例子

char line[LEN];
FILE *cmd = popen("pidof...", "r");

fgets(line, LEN, cmd);
pid_t pid = strtoul(line, NULL, 10);

pclose(cmd);

【讨论】:

    【解决方案3】:

    你知道子进程的名字是shvili,你怎么能启动它却不知道它的名字。

    如果你知道孩子的PID,那么不要使用systemsystem 不是一个行为良好的程序,不要使用它。

    改为使用forkexec

    在父母做:

    #include <unistd.h>
    
    int child_pid = fork();
    if (child_pid == -1) {
       //fork failed do something about it
    } else if (child_pid == 0) {
       //this runs for child
       execl("shvili", NULL);
       //if you get here then exec errored
    } else {
       //This runs for parent
       //child_pid has child pid
       //Add parent code hear.
       wait(…);
    }
    

    解释:

    • ifs 的第一个分支在 fork 错误时运行。
    • 其他
      • 在 2 个单独的进程中:
      • 第二个分支为孩子运行。
      • 第三个分支为父级运行。

    【讨论】:

    • 我只是举了一个例子。我有一个在不同发行版上有不同子进程的进程(因为它在启动时执行不同的 bash 脚本),我想获取子进程的名称。
    • 你还是要知道,调用system或者exec,是不是在变量里面?哪些部分知道?,哪些部分需要知道?
    • 这只是一个例子。实际上,我有一个为不同用户创建会话的过程。在 gnome 上它的孩子是 init --user 但例如在 centos 上它的 gnome-session 进程,我必须编写一个代码来告诉我其中哪个是孩子
    猜你喜欢
    • 2011-04-16
    • 1970-01-01
    • 2015-07-08
    • 2015-03-07
    • 2011-05-05
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    相关资源
    最近更新 更多