当处于子进程中时,如何通过某些信号或 PID 的终止来退出父进程的正确 bash 命令/指令?
答案1
如果我理解正确,那么一个可能的解决方案是trap
使用 shell 进程或命令。
解决方案1
笔记:使用trap
它似乎只有在使用 shell 时才有用。例如,如果您在终端中运行命令或在脚本中运行 shell 代码(如myscript.sh
),您将能够使用trap
.
让我们看一个例子:
输入ps -fH
我当前的父进程(一个zsh
shell),我得到:
%> ps -fH
#Output:
UID PID PPID C STIME TTY TIME CMD
edgar 17932 24608 0 23:37 pts/2 00:00:00 /bin/zsh
edgar 18001 17932 0 23:38 pts/2 00:00:00 ps -fH
现在我将运行一个bash
子进程并ps -H
再次输入:
%> bash
(bash shell) %> ps -fH
#Output:
UID PID PPID C STIME TTY TIME CMD
edgar 17932 24608 0 23:37 pts/2 00:00:00 /bin/zsh
edgar 18012 17932 0 23:38 pts/2 00:00:00 bash
edgar 18030 18012 0 23:38 pts/2 00:00:00 ps -fH
正如您所看到的,bash shell 的父进程带有zsh
PID 17932
。
要获取某个进程的 PPID,您应该使用ps -o ppid= $SOME_PID
.例如,如果你想获取当前bash
进程的父进程 ID,你应该使用:
(bash shell) %> ps -o ppid= 18012
#Output:
17932
或者还有什么更值得推荐的:
(bash shell) %> ps -o ppid= $$
#Output
17932
$$
我们正在获取当前正在运行的进程的进程 ID,在本例中为bash
。
最后,如果您想终止父进程(zsh
在本例中),您应该运行以下命令:
(bash shell) %> trap "echo Killing parent process $(ps -o ppid= $$); kill -9 $(ps -o ppid= $$)" 0
#Or
(bash shell) %> trap "kill -9 $(ps -o ppid= $$)" 0
现在,当您键入exit
或按下时,Ctrl + D父进程zsh
也将被终止:
(bash shell) %> exit
#zsh was killed too, so the terminal will show the following output:
Warning: Program '/bin/zsh' crashed
为了避免zsh 崩溃了消息你可以运行两次bash
shell
解决方案2
使用该strace
命令应该适用于任何进程。
让我们看一个例子:
我们将在后台运行一个进程,并将strace
该进程附加到可以杀死该进程的父进程。
首先,我将在shellbash
中执行zsh
(zsh shell) %> bash
现在,在bash
shell 中,我们将在后台运行一个进程,对于本例,我们将使用该sleep
命令并获取它的 PPID(父进程 ID)。
(bash shell) %> sleep 60& #sleep 1 minute (in background)
processID=$! #with $! we get the pid of the last executed process, in this case the sleep command
parentID=$(ps -o ppid= $processID)
如果我们查看ps -fH
输出,我们会得到如下结果:
UID PID PPID C STIME TTY TIME CMD
edgar 21593 21579 0 00:43 pts/1 00:00:00 /bin/zsh
edgar 22971 21593 0 01:03 pts/1 00:00:00 bash
edgar 23011 22971 0 01:07 pts/1 00:00:00 sleep 60
edgar 23012 22971 0 01:08 pts/1 00:00:00 ps -fH
现在我们要bash
在sleep 60
完成后杀死父进程。为此,我们将使用以下strace -p
命令:
strace -p $processID ; kill -9 $parentID
strace -p 用于使用其 PID 附加进程。
当进程$processID
(睡眠命令)完成时,kill 命令将运行并杀死 $parentID(bash shell)。
笔记:我不确定是否可以strace
在收到信号时执行命令。此方法仅在进程完成后才有效。
上面命令的解释
ps的使用
根据ps --help
:
-f -- 完整列表
--forest -H -- 显示进程层次结构
ps -f
与仅使用相比,输出将显示更多列ps
。我曾经ps -f
了解PPID
每个过程。
With ps -H
(您也可以使用ps --forest
) 如帮助所述将显示进程层次结构,即某个进程的每个子进程将以特殊格式显示。运行ps -H
我得到:
PID TTY TIME CMD
2872 pts/1 00:00:00 zsh
3771 pts/1 00:00:00 bash
7259 pts/1 00:00:00 ps
您可以看到这ps
是 的子进程bash
,而这是 的进程zsh
。
您还可以运行ps f
(这是 BSD 语法)而不是ps -H
:
%> ps f
#Output:
PID TTY STAT TIME COMMAND
2872 pts/1 Ss 0:00 /bin/zsh
3771 pts/1 S 0:00 \_ bash
7495 pts/1 R+ 0:00 \_ ps f
陷阱的使用
的语法trap
是:trap 'commands' SIGNAL
.这意味着当进程接收到特定信息时,SIGNAL
它将执行commands
.您可以输入man trap
以获得更好的描述:
条件可以是 EXIT、0(相当于 EXIT)或使用符号名称指定的信号(不带 SIG 前缀),如基本定义卷中定义的 <signal.h> 标头中的信号名称表中所列。 POSIX.1‐2017。
...
符合 XSI 的系统还允许在与以下信号名称对应的条件下使用数字信号编号:
1 SIGHUP
2 SIGINT
3 SIGQUIT
6 SIGABRT
9 SIGKILL
14 SIGALRM
15 SIGTERM
所以如果你使用trap 'commands' 0
shell,'commands'
退出shell时就会执行trap中指定的内容。
例如,echo
当SIGINT
bash shell 接收到以下代码时,将执行以下代码:
(bash_shell) %> echo Bash PID: $$
#Output:
Bash PID: 8529
(bash_shell) %> trap 'echo Bash got SIGINT signal' 2
(bash_shell) %> kill -SIGINT 8529
#Output:
^CBash got SIGINT signal
您也可以在 bash shell 中kill -SIGINT 8529
按: 。Ctrl+C
笔记:用于trap
某些信号可能不起作用(我已经使用 SIGKILL 进行了测试,但它不起作用)。
使用杀戮
您可以使用man kill
或man 1p kill
来获取有关该命令的更详细说明。
Kill -s 信号名 pid
Kill -l [退出状态]
杀死[-signal_name] pid
Kill [-signal_number] pid ...
-s signal_name
使用 <signal.h> 标头中定义的符号名称之一指定要发送的信号。 signal_name 的值应以与大小写无关的方式进行识别,没有 SIG 前缀。另外,应识别符号名称0,表示信号值零。应发送相应的信号而不是 SIGTERM。
-signal_name
相当于 -s signal_name。-signal_number
指定一个非负十进制整数 signal_number,表示要使用的信号,而不是 SIGTERM,作为对kill() 的有效调用中的 sig 参数。整数值和所使用的 sig 值之间的对应关系如下表所示。指定除下列之外的任何 signal_number 的效果未定义。
0 0
1 SIGHUP
2 SIGINT
3 SIGQUIT
6 SIGABRT
9 SIGKILL
14 SIGALRM
15 SIGTERM
所以命令kill -9 8990
与 相同kill -SIGKILL 8990
。发送SIGKILL
到一个进程将杀死/完成这个进程。