Shell 脚本 - 按名称杀死除我之外的所有进程

Shell 脚本 - 按名称杀死除我之外的所有进程

我有test.sh正在运行的 shell 脚本。

我希望在这个脚本的开头,如果有旧的test.sh正在运行,请先杀死它们。

如果我杀死test.sh所有最新进程也被杀死。

我有什么简单的方法可以做到吗?

答案1

#!/bin/sh

term_handler () {
    if [ "$ok_to_exit" -eq 1 ]; then
        echo 'exiting'
        exit
    else
        echo 'refusing to exit'
    fi
}

trap term_handler TERM

ok_to_exit=0
pkill -f test.sh
ok_to_exit=1

while true; do
    echo 'working...'
    sleep 2
done

该脚本(下面有一个更简单的版本)安装了一个信号处理程序,该函数将在收到信号term_handler后退出脚本TERM如果变量ok_to_exit的值为1

脚本主体中有一个循环,模拟正在执行的某种形式的工作。重要的是,在调用之前pkill(您可以将其更改为您的killall命令),它设置ok_to_exit0,然后立即将其设置为1

当向所有匹配的进程发出TERM信号时,它本身会收到信号,但会拒绝退出。任何其他匹配过程,如果它不处于完全相同的状态(如果您同时启动脚本多次,则可能会发生这种情况),将终止。

运行时,该脚本将输出

refusing to exit
working...
working...
working...

当脚本的另一个副本启动时,它会输出exiting然后终止。

同一脚本的更简单版本:

#!/bin/sh

trap '' TERM
pkill -f test.sh
trap - TERM

while true; do
    echo 'working...'
    sleep 2
done

这简直就是忽略TERM调用期间的信号,pkill然后在继续之前恢复默认信号处理程序。

答案2

不使用信号处理程序的一个好方法是向除您自己之外的每个进程发出信号:

for pid in $(pgrep ${0##*/}); do
    if [[ $pid -ne $$ ]]; then
        kill -s TERM $pid
    fi
done

如果您对 bash 不太熟悉,${0##*/}则会为您提供 的基本名称$0(脚本调用的名称),以便“/path/to/test.sh”变为“test.sh”。

答案3

启动两个以上的实例时会遇到一些麻烦,但您可以像这样使用pgrep/ :pkill

#!/bin/sh

while [ "$(pgrep -c -f test.sh)" -gt 1 ]
do
  pkill --oldest -f test.sh
done

# rest of your script

调整“test.sh”参数以更精确地匹配进程名称本身!

举些例子:

/bin/sh ./test.sh

或者

/bin/sh /full/path/to/test.sh

或者

/bin/bash ./test.sh

或者

sh test.sh

...这样您就不会意外匹配其他任何内容。

答案4

如果全部你的处决test.sh 总是通过这样的看守检查,那么你可以这样做:

pid=$(pgrep -o -f "/test.sh( |$)") && [ ${pid} -ne ${$} ] && kill $pid

上面的行仅杀死最旧的执行,除非它也是当前的执行,无论它是如何被调用的。

但为了万一你想绝对确保以前的执行没有漏过检查,你可以将上面的行放入一个while循环中,如下所示:

while pid=$(pgrep -o -f "/test.sh( |$)") && [ ${pid} -ne ${$} ] ; do
    kill $pid
done

以上杀任何以前的处决test.sh,但他们被称为。

根据您的需要,您可能需要一个还考虑命令的特定文字参数的选择标准。

您可以通过在双引号中包含您想要检查的任何参数来完成此操作,如下所示:

注意:我只显示了pgrep上面代码中使用的部分

pgrep -o -f "/test.sh +arg1 +arg2 *$"

额外的+*$ 必须与这些确切的参数匹配。 (在此示例中,文字字符串arg1arg2)。

您还可以传递变量,因此,例如,一种理想的变体可能是仅终止那些使用与当前执行相同的参数运行的先前执行:

pgrep -o -f "/test.sh +${*} *$"

这里${*}翻译为当前执行的所有参数。

基本上,双引号内的字符串可以是任何有效的正则表达式,这可以帮助您匹配要终止的确切执行,这对于避免终止外部进程非常重要。

相关内容