【问题标题】:starting a new process group from bash script从 bash 脚本启动一个新的进程组
【发布时间】:2015-08-25 19:52:50
【问题描述】:

我基本上想在一个新的进程组中运行一个脚本(它调用更多脚本),以便我可以向脚本调用的所有进程发送信号。

在 Linux 中,我发现 setsid 可以帮助我做到这一点,但这在 FreeBSD 上不可用。

setsid 的语法(由 util-linux-ng 提供)。

setsid /path/to/myscript

然而,我了解到会话和进程组并不相同。但是开始一个新的会话也解决了我的问题。

【问题讨论】:

标签: bash unix process signals freebsd


【解决方案1】:

会话和组不是一回事。让我们把事情弄干净:

一个会话由一个或多个进程组组成,并且可以有一个控制终端。当会话有一个控制终端时,该会话在任何时候都只有一个前台进程组和一个或多个后台进程组。在这种情况下,前台进程组中的每个进程都可以看到所有终端生成的信号和输入。

此外,当会话具有控制终端时,shell 进程通常是会话领导者,指示哪个进程组是前台进程组(隐含地使其他组成为后台进程组)。组中的进程通常由线性管道放置在那里。例如,ls -l | grep a | sort 通常会创建一个新的进程组,其中lsgrepsort 存在。

支持作业控制的 Shell(也需要内核和终端驱动程序的支持),例如 bash,为每个调用的命令创建一个新的进程组——如果你调用它在后台运行(使用& 表示法),该进程组未获得终端的控制权,shell 将其设为后台进程组(而前台进程组仍然是 shell)。

因此,如您所见,在这种情况下,您几乎肯定不想创建会话。您想要创建会话的典型情况是,如果您正在守护进程,但除此之外,创建新会话通常没有多大用处。

您可以将脚本作为后台作业运行,正如我所提到的,这将创建一个新的进程组。由于fork() 继承了进程组ID,因此脚本执行的每个进程都将在同一个组中。例如,考虑这个简单的脚本:

#!/bin/bash

ps -o pid,ppid,pgid,comm | grep ".*"

这会打印如下内容:

  PID  PPID  PGID COMMAND
11888 11885 11888 bash
12343 11888 12343 execute.sh
12344 12343 12343 ps
12345 12343 12343 grep

如您所见,execute.shpsgrep 都在同一个进程组(PGID 中的值)。

所以你想要的只是:

/path/to/myscript &

然后你可以用ps -o pid,ppid,pgid,comm | grep myscript查看myscript的进程组ID。要向组发送信号,请将其发送给组长(PGID 是组长的PID)。发送到组的信号会传递给该组中的每个进程。

【讨论】:

  • 我想从一个主脚本调用我的脚本(比如说 script-1)。我希望这个脚本在一个新的进程组下运行。在后台调用 script-1 不会在新进程组下启动它。
  • 在后台运行命令会将其放在另一个组中。但是,如果你想运行一些东西,例如使用bashreadbuiltin,有没有办法在新的进程组中启动这样的脚本?我想要新进程组的原因是,如果按下 Ctrl+C,则 SIGINT 只会传递给该组。
  • “作业控制在非交互模式下默认关闭”(stackoverflow.com/a/690297/18096) 而且似乎只有在启用作业控制时,后台管道才会获得自己的进程组
【解决方案2】:

使用 FreeBSD,您可以尝试使用 script 命令,该命令将在内部执行 setsid 命令。

stty -echo -onlcr   # avoid added \r in output
script -q /dev/null /path/to/myscript
stty echo onlcr
# sync  # ... if terminal prompt does not return

【讨论】:

    【解决方案3】:

    这并不完全是答案,而是基于名称的替代方法。

    您可以为所有进程使用名称的公共部分。例如,对于以下所有进程,我们有 my_proc_group_29387172 部分:

    -rwxrwxr-x.   my_proc_group_29387172_microservice_1
    -rwxrwxr-x.   my_proc_group_29387172_microservice_2
    -rwxrwxr-x.   my_proc_group_29387172_data_dumper
    

    生成所有这些(并且尽可能多):

    ADDR=1 ./my_proc_group_29387172_microservice_1
    ADDR=2 ./my_proc_group_29387172_microservice_1
    ADDR=3 ./my_proc_group_29387172_microservice_2
    ./my_proc_group_29387172_data_dumper
    

    当你想杀死所有进程时,你可以使用 pkill 命令(模式杀死)或带有 --regexp 参数的killall: p>

    pkill my_proc_group_29387172
    

    好处:) - 您可以在任何时间(或任何一天)从任何脚本启动任意数量的进程。

    缺点:( - 如果无辜的进程与你的模式有共同的名称部分,你可以杀死它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-10
      • 1970-01-01
      相关资源
      最近更新 更多