按 Ctrl-C 停止 bash 脚本,但不会停止脚本调用的 PHP 脚本

按 Ctrl-C 停止 bash 脚本,但不会停止脚本调用的 PHP 脚本

我需要每隔几分钟运行几个脚本。逻辑是用 PHP 编写的,效果很好。为了保持整体性,我编写了下面的 bash 脚本,它也运行良好。

#!/bin/bash

calculaDiff() {
    DIFF=0

    while [ "$DIFF" -eq "0" ]; do
        DIFF=`php calculaDiff.php`
    done;
}

# need to calculate pending diffs
calculaDiff

# main loop
while true; do
    CAPTURA=`php capturaRelatorio.php`
    if [ "$CAPTURA" -eq "0" ]; then
        calculaDiff
    fi

    VERIFICA=`php verificaLimites.php`

done

脚本capturaRelatorio.php里面有一个 sleep 函数,因为我只能每 N 分钟处理一次。它会打印一条消息,说明它正在休眠 S 秒,这样我就可以监视它。

如果我调用 bash 脚本并在此时按下Ctrl+ C,当它处于休眠状态时,它会终止 bash 脚本,但不会终止被调用的 php 脚本。我知道有一个不同的进程正在运行它。

那么,有没有办法杀死 bash 脚本和每个“子脚本”?还是我应该采用另一种方法来运行这些脚本?

答案1

从这个答案中:bash - 如何终止 shell 的所有子进程? - 堆栈内存溢出

如果你只关心杀死直接的孩子,你应该能够做到

pkill -P $$

-P

-P, --parent ppid,...
      Only match processes whose parent process ID is listed.

表示$$当前进程的PID。

如果您需要终止子进程及其可能启动的任何进程(孙进程等),您应该能够使用针对该问题的不同答案中的函数:

kill_descendant_processes() {
    local pid="$1"
    local and_self="${2:-false}"
    if children="$(pgrep -P "$pid")"; then
        for child in $children; do
            kill_descendant_processes "$child" true
        done
    fi
    if [[ "$and_self" == true ]]; then
        kill "$pid"
    fi
}

像这样

kill_descendant_processes $$ true

这将终止当前进程及其所有子进程。您可能希望从陷阱处理程序中调用此方法。也就是说,当您按下ctrl+时c,您的脚本将被发送SIGINT,您可以捕获该信号并处理它。例如:

trap cleanup INT

cleanup() {
    kill_descendant_processes $$ true
}

答案2

您可以更新 bash 脚本以捕获 ctrl+c:

trap control_c SIGINT

function control_c() {
    echo "## Trapped CTRL-C"
    ps -ef | grep php | grep -v grep | awk '{ print $2 }' > php.kill
    for i in $(cat php.kill)
    do
        kill -9 $i > /dev/null
    done
    rm php.kill
}

相关内容