我有一个这样的脚本:
pid = $(ps -ef | grep my-service | awk '{print $2}')
这给了我正在运行的进程的 PID my-service
。我想更新我的脚本以处理正在运行的多个进程,并杀死my-service
除最新进程之外的所有旧进程。但如果只有一个进程在运行,则将其杀死。我怎么做?
答案1
pgrep
( 和pkill
) 有一些对此任务有用的参数,例如-c
( --count
) 用于计算进程数,-n
( --newest
) 用于仅获取最新的 pid。 (man pgrep
了解更多)
所以我们可以使用这个case
声明。如果没有返回 pid,我们就退出,如果有,我们就终止这个进程。如果发现多个进程,我们会针对grep -v
所有 pid 排除最新的 pid,然后通过管道传输到kill
.
#!/bin/bash
die="my-service"
case $(pgrep -cf "$die") in
0) exit 0 ;;
1) pkill -f "$die" ;;
*) grep -v $(pgrep -nf "$die") <(pgrep -f "$die") | xargs kill ;;
esac
注意:上面-f
使用了参数,这是匹配完整的命令,如果我们只想匹配进程名称,则不应该使用它。从man pgrep
:
-f,--完整
该模式通常仅与进程名称匹配。设置 -f 时,将使用完整命令行。
答案2
假设 procps-ngps
和未修改的$IFS
,你可以这样做:
set -- $(ps -o pid= --sort=-start_time -C my-service)
case $# in
(0) ;;
(1) kill "$1";;
(*) shift; kill "$@"
esac
set
分配位置参数( $1
, $2
...) 到名称为 的进程的 pid my-service
,按start_time
(最近启动的最先)反向排序。
然后根据它们的编号($#
),如果为 0,我们不执行任何操作,如果为 1,则杀死它,对于任何其他数字,shift
丢弃最小的,并杀死其余的。
(注意ps -C name
匹配确切地在完整的进程名称上,而不是在 报告的 arg 列表上ps -f
)