rsync 抑制 SIGINT 以捕获外部陷阱

rsync suppress SIGINT for trap outside

我正在尝试构建一个通用的 retry shell 函数,以在上次失败时重新 运行 指定的 shell 命令几次,这是我的代码:

retry() {
    declare -i number=
    declare -i interrupt=0
    trap "echo Exited!; interrupt=1;" SIGINT SIGTERM SIGQUIT SIGKILL

    shift

    for i in `seq $number`; do
      echo "\n-- Retry ${i}th time(s) --\n"

      $@

      if [[ $? -eq 0 || $interrupt -ne 0 ]]; then
        break;
      fi
    done
}

它非常适合wgetcurl 和其他各种常用命令。但是,如果我 运行

retry 10 rsync local remote

,传输过程中发送ctrl+c打断,报

rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(700) [sender=3.1.3]

似乎rsync抑制了内部的SIGINT和其他一些相关信号,然后return向外部调用者发送了一个代码20。这个 return 代码没有使循环中断,然后我发送几个 ctrl+c 来中断下一个 rsync 命令。它仅在最后一次 ctrl+c 时打印 Exited! 并且 trap 捕获它。

问题:

  1. 为什么第一个return代码20没有使循环中断?

  2. 如何让trap捕捉到SIGINT信号但是rsync,如果没有,我该怎么办?

Why does it first return code 20 didn't make the loop break?

你是对的,rsync 确实捕获了某些信号并以 RERR_SIGNAL (20) 退出。

How to let the trap catch the SIGINT signal but rsync, if not, what should I do?

因为 rsync 有它自己的处理程序,你不能做任何事情(可以使用一些 hack 来覆盖 rsync 中的信号处理程序,例如 LD_PRELOAD。但它可能是不必要的复杂)。由于您的陷阱在当前 shell 中,您不知道 "command" 是否发出信号或以非零退出。

我假设你希望你的 retry 是通用的并且你不希望对 rsync 进行特殊处理(例如,不同的命令可能会以 75 信号退出而你不'想处理特殊情况)。

问题是您的陷阱处理程序未激活,因为当前进程 运行ning 进程 (rsync) 接收到信号。您可以在后台 运行 您的命令并等待它完成。这将允许您从 retry 捕获信号。收到信号后,它会简单地杀死子进程。

#!/bin/bash

retry()
{
    declare -i number=
    declare -i i
    declare -i pid
    declare -i interrupted=0

    trap "echo Exiting...; interrupted=1" SIGINT SIGTERM SIGQUIT
    shift

    # Turn off "monitor mode" so the shell doesn't report terminating background jobs.
    set +m

    for ((i = 0; i < number; ++i)); do
        echo "\n-- Retry ${i}th time(s) --\n"
        $@ &
        pid=$!

        # If command succeeded, break
        wait $pid && break

        # If we receive one of the signals, break
        [[ $interrupted == 1 ]] && kill $pid && break
    done

    # Switch back to default behaviour
    set -m
    trap - SIGINT SIGTERM SIGQUIT
}

注意SIGKILL是抓不到的。所以给它设下陷阱也没有意义。所以我已经删除了它。