我想在单个 shell 上运行多个命令(进程)。都有自己的连续输出,不停歇。在后台运行它们Ctrl- C。我想将它们作为单个进程(子shell,也许?)运行,以便能够用Ctrl-停止所有这些进程C。
具体来说,我想使用mocha
(监视模式)运行单元测试,运行服务器并运行一些文件预处理(监视模式),并在一个终端窗口中查看每个测试的输出。基本上我想避免使用一些任务运行器。
我可以通过在后台运行进程 ( &
)来实现它,但是我必须将它们放到前台来阻止它们。我想要一个包装它们的过程,当我停止这个过程时,它会停止它的“孩子”。
在man page
,它说:
kill [ -s signal | -p ] [ -a ] [ -- ] pid ...
pid... Specify the list of processes that kill should signal. Each pid can be one of five things:
0 All processes in the current process group are signaled
Run Code Online (Sandbox Code Playgroud)
我在 bash 中尝试这样:
$ man kill &
[1] 15247
$
[1]+ Stopped man kill
$ kill 0
$ ps
15247 pts/41 00:00:00 man
Run Code Online (Sandbox Code Playgroud)
这里0
用作pid
. 据我了解,kill 0
将杀死当前进程中的所有进程,其中包括pid15247 …
在“ /sf/ask/912670041/ ”中,我看到所有答案都提到了ps
,没有提到/proc
。
“ps”似乎不是很便携(Android 和 Busybox 版本需要不同的参数),我希望能够使用简单且便携的工具列出带有 pgid 的 pid。
在 /proc/.../status 我看到Tgid:
(线程组 ID),Gid:
(组 ID 用于安全,而不是用于将进程分组在一起),但不是PGid:
...
ps
从 pid 获取 pgid 的其他(不使用)方法是什么?
所以我到处都在读这个命令应该终止父进程的所有子进程:
kill -- -$$
Run Code Online (Sandbox Code Playgroud)
在 kill 命令中使用负 ID 会引用一个 PGID,并且从我看到的示例来看,子进程的 PGID 应该是父进程的 PID,但在我的系统中并非如此。
在我的系统上,子脚本的 PGID 与父脚本的 PGID 相同,结果是 bash。
这里发生了什么?示例是错误的还是我的系统设置不同?
我需要实现的是在不终止父进程的情况下终止子进程,因此我不想向父进程所在的 PGID 发送终止信号。
我读到会话的 ID 与通过setsid()
系统调用创建会话的进程的 pid 相同,但我没有找到有关如何设置进程组 ID 的任何信息。进程组 ID 是否与创建进程组的进程的 pid 相同?
(Re-posting in unix per the suggestion in /sf/ask/960287611/)
The short question is, what should a shell do if it is in an orphaned process group that doesn't own the tty? But I recommend reading the long question because it's amusing.
Here is a fun and exciting way to turn your laptop into a portable space heater, using your favorite shell (unless you're one of those tcsh weirdos):
#include <unistd.h>
int main(void) {
if (fork() == 0) {
execl("/bin/bash", "/bin/bash", …
Run Code Online (Sandbox Code Playgroud) 进程组和作业有什么区别?如果我输入,pr * | lpr
那么它既是进程组又是工作?进程组 ID 和作业 ID 之间究竟有什么区别?
编辑:我知道它看起来类似于工作和流程之间的区别是什么?,但略有不同。另外,我没有从这个线程中理解这个概念。
我想从另一个 bash 脚本启动一个 bash 脚本,但在它自己的进程组中启动它,就像从终端运行它一样。
有几个类似的问题,但我找不到与我的示例相匹配的答案。
拿这两个脚本
$ cat main.sh
#! /usr/bin/env bash
set -e
echo if this has been started in its own group the following will pass
ps -o ppid,pgid,command $$
ps -o pgid | grep $$
echo passed
$ cat wrapper.sh
#! /usr/bin/env bash
set -e
./main.sh
Run Code Online (Sandbox Code Playgroud)
当我main.sh
单独运行时,终端将其放入自己的组中:
$ ./main.sh
if this has been started in its own group the following will pass
PPID PGID COMMAND
20553 1276 bash ./main.sh
1276
1276
1276
passed
$ …
Run Code Online (Sandbox Code Playgroud) 在 POSIX 中,进程通过两个基本层次结构相互“关联”:
父进程和子进程的层次结构。
会话和进程组的层次结构。
用户进程通过setpgid
和对后者有很大的控制权setsid
,但他们对前者的控制很少——父进程 ID 在进程生成时设置,并在父进程退出时由内核更改(通常为 PID 1 ),否则它不会改变。回想起来,我一直在想亲子关系到底有多重要。
总结一下我目前的理解:
从父进程的角度来看,父子关系显然很重要,因为各种系统调用,如wait
和setpgid
,只允许在子进程中使用。
会话-组-进程关系显然对所有进程都很重要,包括会话领导者和会话中的其他进程,因为像kill
对整个进程组进行操作的系统调用setpgid
只能用于在同一会话中加入一个组,并且所有进程SIGHUP
如果会话领导者退出,会话的前台进程组中的消息将被发送。
更重要的是,从父级的角度来看,这两个层次结构显然是相关的,因为setsid
只影响新的子级,setpgid
只能用于子级,但从子级的角度来看它们似乎基本无关(因为父进程死亡没有任何影响)在进程的组或会话上)。
然而,显然没有任何理由让子进程关心它的当前父进程是什么。因此,我有以下问题:从子进程的角度来看,的当前值是否getppid()
有任何重要性,除了可能确定其生成过程是否已退出?
换一种方式提出同样的问题,假设同一个程序以两种不同的方式从同一个父级产生两次:
第一个孩子以通常的方式产生,fork()
紧接着是exec()
.
第二个子进程是间接产生的:父进程调用fork()
,然后子进程也调用fork()
,而孙子进程调用exec()
。然后直接子进程退出,因此孙子进程成为孤儿,它的 PPID 被重新分配给 PID 1。
在这个假设场景中,假设所有其他条件都相同,是否有任何合理的程序有理由做出不同的行为?到目前为止,我的结论似乎是“不”,因为会话保持不变,进程继承的文件描述符也是如此……但我不确定。
注意:我不认为“获取父 PID 与其通信”是该问题的有效答案,因为孤立程序通常不能依赖于将其 PPID 设置为 1(某些系统将孤立进程的 PPID 设置为某些其他值),因此避免竞争条件的唯一方法是getpid()
在分叉之前 …
kill -TERM -PID
Run Code Online (Sandbox Code Playgroud)
应该杀死PID及其所有子进程。
但这在 openSUSE 上不起作用,它总是告诉我没有这样的进程 -PID,无论我使用什么 PID。
因此,如果此特定版本的 kill 不支持负 PID 选项,那么杀死一组进程的最佳方法是什么?
背景:
我有一个 shell 脚本正在运行。在脚本中,我使用 wget 下载东西。所以脚本是父进程,wget 是子进程。我想使用 kill -TERM -PID_OF_SCRIPT 杀死它们
process ×10
process-groups ×10
bash ×2
kill ×2
shell-script ×2
command-line ×1
job-control ×1
linux ×1
posix ×1
proc ×1
shell ×1
signals ×1
tty ×1