2012-03-08 3 views
9

Контекст:Bash не улавливать прерывания во время Rsync/подоболочка EXEC заявления

У меня есть Баш скрипт, который содержит подоболочку и ловушку для EXIT pseudosignal, и это не правильно улавливать прерывания во время rsync. Вот пример:

#!/bin/bash 
logfile=/path/to/file; 
directory1=/path/to/dir 
directory2=/path/to/dir 

cleanup() { 
    echo "Cleaning up!" 
    #do stuff 
    trap - EXIT 
} 

trap '{ 
    (cleanup;) | 2>&1 tee -a $logfile 
}' EXIT 

(
    #main script logic, including the following lines: 
    (exec sleep 10;);   
    (exec rsync --progress -av --delete $directory1 /var/tmp/$directory2;); 

) | 2>&1 tee -a $logfile 
trap - EXIT #just in case cleanup isn't called for some reason 

Идея сценария заключается в следующем: большинство важных логики работает в субоболочке, который передается по конвейеру через tee и в лог-файл, так что я не должен tee каждый линия основная логика, чтобы все это регистрировалось. Всякий раз, когда заканчивается подоболочка или сценарий останавливается по какой-либо причине (псевдосигнал EXIT должен фиксировать все эти случаи), ловушка будет перехватывать его и запускать функцию cleanup(), а затем удалять ловушку. Командыи sleep (сон как раз пример) выполняются через exec, чтобы предотвратить создание процессов зомби, если я убью родительский скрипт во время их работы, и каждая потенциально долго работающая команда завернута в свою собственную подоболочку так что, когда закончится exec, он не завершит весь сценарий.

Проблема:

Если я прерываю скрипт (через kill или CTRL + C) во время ехеса/субоболочки завернутых sleep команду, ловушка работает должным образом, и я вижу «Очистка!» эхом и протоколирован. Если я прерываю скрипт во время команды rsync, я вижу rsync конец и записываю rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(544) [sender=3.0.6] на экран, а затем скрипт просто умирает; без очистки, без улавливания. Почему прерывание/убийство rsync не запускают ловушку?

Я попытался использовать переключатель --no-detach с rsync, но ничего не изменил. У меня есть bash 4.1.2, rsync 3.0.6, centOS 6.2.

+0

Это не повод для вашей проблемы, но ваш журнал не является надежным, потому что вы одновременно записываете две разные программы в один и тот же файл. – ceving

+0

ваш 'trap - EXIT' находится в подоболочке (явно), поэтому он не будет иметь эффекта после возвращения функции очистки. – sehe

+0

Запуск exec в подоболочке такой же, как и обычный запуск команды - вам не нужно дополнительная пунктуация. –

ответ

1

Как насчет имея все выходные данные из точки X перенаправлены на тройник без необходимости повторять везде и неразбериха со всеми суб-оболочек и Execs ... (надеюсь, я не пропустить что-то)

#!/bin/bash 
logfile=/path/to/file; 
directory1=/path/to/dir 
directory2=/path/to/dir 

exec > >(exec tee -a $logfile) 2>&1 

cleanup() { 
    echo "Cleaning up!" 
    #do stuff 
    trap - EXIT 
} 
trap cleanup EXIT 

sleep 10 
rsync --progress -av --delete $directory1 /var/tmp/$directory2 
+0

Это было мое первое решение, но некоторые из наших окружений не могут выполнить перенаправление из-за странной версии Bash или чего-то еще ... поэтому я прибегнул к «обернуть все это в блок и указать все на тройник ". Хороший момент. –

+0

@ZacB Можете ли вы уточнить «странную версию bash»? В некоторых ситуациях (при запуске как '/ bin/sh') он запускает n режим совместимости Posix ... Если это так, добавьте' set + o posix' до 'exec' – nhed

+0

Это была ситуация @nhed; он был разрешен путем переключения на '/ bin/bash'. –

1

ПРЕРЫВАЙТЕ будет правильно поймали, если добавить INT в ловушку

trap '{ 
    (cleanup;) | 2>&1 tee -a $logfile 
}' EXIT INT 

Bash будет улавливать прерывания правильно. Тем не менее, это не отвечает на вопрос, почему сценарий ловушки при выходе, если sleep перепутаны, и почему он не запускается на rsync, но делает скрипт работать так, как предполагается. Надеюсь это поможет.

+0

Это выглядело правильно, но я реализовал его, и он имел противоположность желаемому эффекту. Если я добавлю INT в вызовы trap, оператор 'sleep' больше не запускает ловушку, а' rsync' по-прежнему не работает. Когда я удаляю INT (ничего не изменяя), 'sleep' снова запускает ловушку. –

+0

Удалите последнюю ловушку «на всякий случай», и скрипт должен хорошо работать с ловушками EXIT. Однако INT в ловушке, вызывающей очистку, должен быть правильным способом борьбы с прерываниями. Несвязанный, но, как писал sehe, ловушка в подоболочке ничего не делает. –

0

Ваша оболочка может быть выполнена с возможностью выхода на ошибку:

bash # enter subshell 
set -e 
trap "echo woah" EXIT 
sleep 4 

Если вы прервали sleep (^ C), то подоболочка выйдет из-set -e и печати woah в процессе.

Кроме того, немного несвязанный: Ваш trap - EXIT в субоболочке (явно), поэтому он не будет иметь эффект после того, как функция очистки возвращает

1

В дополнение к set -e, я думаю, что вы хотите set -E:

If set, any trap on ERR is inherited by shell functions, command substitutions, and commands executed in a sub‐shell environment. The ERR trap is normally not inherited in such cases.

В качестве альтернативы вместо того, чтобы обертывать ваши команды в подоболочки, используйте фигурные скобки, которые все равно дадут вам возможность перенаправлять выходы команд, но будут выполнять их в текущей оболочке.