rsyn c подавить SIGINT для ловушки снаружи - PullRequest
0 голосов
/ 27 февраля 2020

Я пытаюсь создать универсальную c retry функцию оболочки для повторного запуска указанной команды оболочки, если она не удалась в последний раз, вот мой код:

retry() {
    declare -i number=$1
    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
}

Отлично работает для wget, curl и других всевозможных общих команд. Однако, если я запускаю

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 и другие некоторые связанные сигналы внутри, затем возвращает код 20 внешнему абоненту. Этот код возврата не сломал l oop, затем я отправил несколько ctrl + c, чтобы прервать следующие rsync команды. Он печатает Exited! только для последних ctrl + c и trap перехватывает его.

Вопросы :

  1. Почему это происходит первым? код возврата 20 не сделал перерыв l oop?

  2. Как разрешить trap перехватить сигнал SIGINT, но rsync, если нет, что мне делать?

1 Ответ

1 голос
/ 29 февраля 2020

Почему первый код возврата 20 не остановил l oop?

Вы правы, что rsync перехватывает определенные сигналы и выходит с RERR_SIGNAL (20).

Как разрешить ловушке ловить сигнал SIGINT, но rsyn c, если нет, что мне делать?

Поскольку rsync имеет свои собственные обработчики, вы ничего не можете сделать (могли бы использовать некоторые хаки для переопределения обработчиков сигналов в rsync, например, LD_PRELOAD. Но это может быть излишне сложно). Поскольку ваши ловушки находятся в текущей оболочке, вы не будете знать, была ли сигнализирована «команда» или выход с ненулевым значением.

Я бы предположил, что вы хотите, чтобы ваш retry был обобщенным c, и вам не нужна специальная обработка rsync (например, другая команда может завершиться с 75 для сигналов, и вы не не хочу иметь дело с особыми случаями.)

Проблема в том, что ваши обработчики ловушек не активны, так как сигнал получен текущим процессом, запущенным процессом (rsync). Вместо этого вы можете запустить команду в фоновом режиме и дождаться ее завершения. Это позволит вам поймать сигналы от retry. Получив сигнал, он просто убивает дочерний процесс.

#!/bin/bash

retry()
{
    declare -i number=$1
    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 не может быть перехвачен. Так что нет смысла ставить ловушку для этого. Итак, я удалил его.

...