如何获取后台进程的进程ID?
- 2024-10-09 09:11:00
- admin 原创
- 76
问题描述:
我从我的 shell 脚本启动一个后台进程,并且我想在脚本完成时终止该进程。
如何从我的 shell 脚本中获取此进程的 PID?据我所知,变量$!
包含当前脚本的 PID,而不是后台进程的 PID。
解决方案 1:
您需要在启动后台进程时保存其 PID:
foo &
FOO_PID=$!
# do other stuff
kill $FOO_PID
您不能使用作业控制,因为这是交互功能,并且与控制终端绑定。脚本不一定连接终端,因此作业控制不一定可用。
解决方案 2:
您可以使用jobs -l
命令来执行特定的任务
^Z
[1]+ Stopped guard
my_mac:workspace r$ jobs -l
[1]+ 46841 Suspended: 18 guard
在这种情况下,46841 是 PID。
从help jobs
:
-l 报告作业的进程组ID和工作目录。
jobs -p
是另一个仅显示 PID 的选项。
解决方案 3:
$$
是当前脚本的 pid$!
是最后一个后台进程的 pid
下面是一个 bash 会话的示例记录(%1
指的是从中看到的后台进程的序数jobs
):
$ echo $$
3748
$ sleep 100 &
[1] 192
$ echo $!
192
$ kill %1
[1]+ Terminated sleep 100
解决方案 4:
杀死 bash 脚本的所有子进程的更简单的方法:
pkill -P $$
该-P
标志的工作方式与pkill
和相同pgrep
- 它获取子进程,只有pkill
子进程被终止并且pgrep
子 PID 被打印到标准输出。
解决方案 5:
这是我做的。看看吧,希望它能有所帮助。
#!/bin/bash
#
# So something to show.
echo "UNO" > UNO.txt
echo "DOS" > DOS.txt
#
# Initialize Pid List
dPidLst=""
#
# Generate background processes
tail -f UNO.txt&
dPidLst="$dPidLst $!"
tail -f DOS.txt&
dPidLst="$dPidLst $!"
#
# Report process IDs
echo PID=$$
echo dPidLst=$dPidLst
#
# Show process on current shell
ps -f
#
# Start killing background processes from list
for dPid in $dPidLst
do
echo killing $dPid. Process is still there.
ps | grep $dPid
kill $dPid
ps | grep $dPid
echo Just ran "'"ps"'" command, $dPid must not show again.
done
然后只需以适当的权限运行它:./bgkill.sh
当然
root@umsstd22 [P]:~# ./bgkill.sh
PID=23757
dPidLst= 23758 23759
UNO
DOS
UID PID PPID C STIME TTY TIME CMD
root 3937 3935 0 11:07 pts/5 00:00:00 -bash
root 23757 3937 0 11:55 pts/5 00:00:00 /bin/bash ./bgkill.sh
root 23758 23757 0 11:55 pts/5 00:00:00 tail -f UNO.txt
root 23759 23757 0 11:55 pts/5 00:00:00 tail -f DOS.txt
root 23760 23757 0 11:55 pts/5 00:00:00 ps -f
killing 23758. Process is still there.
23758 pts/5 00:00:00 tail
./bgkill.sh: line 24: 23758 Terminated tail -f UNO.txt
Just ran 'ps' command, 23758 must not show again.
killing 23759. Process is still there.
23759 pts/5 00:00:00 tail
./bgkill.sh: line 24: 23759 Terminated tail -f DOS.txt
Just ran 'ps' command, 23759 must not show again.
root@umsstd22 [P]:~# ps -f
UID PID PPID C STIME TTY TIME CMD
root 3937 3935 0 11:07 pts/5 00:00:00 -bash
root 24200 3937 0 11:56 pts/5 00:00:00 ps -f
解决方案 6:
pgrep
可以获取父进程的所有子进程 PID。如前所述,$$
这是当前脚本的 PID。因此,如果您想要一个可以在执行后自行清理的脚本,那么以下代码应该可以解决问题:
trap 'kill $( pgrep -P $$ | tr "
" " " )' SIGINT SIGTERM EXIT
解决方案 7:
您可能还可以使用 pstree:
pstree -p user
这通常为“用户”提供所有进程的文本表示,而 -p 选项提供进程 ID。据我所知,它不依赖于进程是否由当前 shell 拥有。它还显示派生。
解决方案 8:
如果您无法在启动作业后直接获取 PID,您也可以尝试此操作并稍后获取 PID:
foo &
# do some stuff and then
pid=$(ps -aux | grep foo | grep -v grep | tr -s ' ' | cut -d -f2)
kill $pid
解释:
ps
获取所有进程的信息,包括命令grep
正在过滤你的命令,第二个 grep 不检索 grep 本身的 pidtr
正在删除 cut 的重复空格cut
获取 PID 列(本例中为 2)
解决方案 9:
我在配置各种基础设施对象时多次遇到过这个问题。很多时候你需要使用 kubectl 或临时端口转发的临时代理。我发现timeout命令是解决这些问题的好方法,因为它允许我的脚本自成一体,我可以确保该过程会结束。我尝试设置较小的超时时间,如果仍然需要,则重新运行脚本。
解决方案 10:
几年后,这里有一行代码可以查找命令的 PID:
read -p "查找 PID 的命令名称是什么?" pname ; jobs -l | grep $pname | awk '{ print "命令 PID 为 "$2}
它的作用:询问进程名称变量 pname 列出所有作业并使用 grep 搜索 $pname 使用 awk 清晰地返回结果。
例如,通过修改 awk 步骤并传递给 bash,可以轻松修改以停止某个进程
read -p “查找 PID 的命令名称是什么?” pname ; jobs -l | grep $pname | awk '{ print “kill”$2} | bash
或者对于任何进程/命令“foo”非交互地非常简洁:
设置 pname=foo ; jobs -l | grep $pname | awk '{ print "命令 PID 为 "$2}
但请注意,这假设只有一个名为 foo 的进程。万一遇到这种情况,可以添加一个答案数量的测试,如果答案数量大于 1,则提出一个进程 ID 列表
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件