Нет способа иметь несколько обработчиков для одной и той же ловушки, но один и тот же обработчик может делать несколько вещей.
Единственное, что мне не нравится в других ответах, делающих одно и то же, - это использование строковых манипуляций для получения текущей функции ловушки. Есть два простых способа сделать это: массивы и аргументы. Аргументы самые надежные, но я сначала покажу массивы.
Массивы
При использовании массивов вы полагаетесь на тот факт, что trap -p SIGNAL
возвращает trap -- ??? SIGNAL
, поэтому независимо от значения ???
в массиве есть еще три слова.
Поэтому вы можете сделать это:
declare -a trapDecl
trapDecl=($(trap -p SIGNAL))
currentHandler="${trapDecl[@]:2:${#trapDecl[@]} - 3}"
eval "trap -- 'your handler;'${currentHandler} SIGNAL"
Итак, давайте объясним это. Сначала переменная trapDecl
объявляется как массив. Если вы делаете это внутри функции, она также будет локальной, что удобно.
Далее мы присваиваем вывод trap -p SIGNAL
массиву. В качестве примера предположим, что вы запустили это после получения источника osht (модульное тестирование для оболочки), и что сигнал равен EXIT
. Вывод trap -p EXIT
будет trap -- '_osht_cleanup' EXIT
, поэтому назначение trapDecl
будет заменено следующим образом:
trapDecl=(trap -- '_osht_cleanup' EXIT)
В скобках указано обычное присвоение массива, поэтому trapDecl
становится массивом с четырьмя элементами: trap
, --
, '_osht_cleanup'
и EXIT
.
Затем мы извлекаем текущий обработчик, который может быть встроен в следующую строку, но для пояснения я сначала назначил его переменной. Упрощая эту строку, я делаю это: currentHandler="${array[@]:offset:length}"
, который является синтаксисом, используемым Bash для выбора элементов length
, начинающихся с элемента offset
. Поскольку он начинает отсчет с 0
, число 2
будет '_osht_cleanup'
. Далее ${#trapDecl[@]}
- это количество элементов внутри trapDecl
, которое в примере будет 4. Вы вычитаете 3, потому что есть три элемента, которые вам не нужны: trap
, --
и EXIT
. Мне не нужно использовать $(...)
вокруг этого выражения, потому что арифметическое расширение уже выполняется для аргументов offset
и length
.
Последняя строка выполняет eval
, который используется для того, чтобы оболочка интерпретировала кавычки из вывода trap
. Если мы сделаем подстановку параметров в этой строке, в примере она расширится до следующего:
eval "trap -- 'your handler;''_osht_cleanup' EXIT"
Не путайте двойные кавычки в середине (''
). Bash просто объединяет две строки кавычек, если они находятся рядом друг с другом. Например, '1'"2"'3''4'
расширен до 1234
с помощью Bash. Или, чтобы привести более интересный пример, 1" "2
- это то же самое, что и "1 2"
. Итак, eval берет эту строку и оценивает ее, что эквивалентно выполнению этого:
trap -- 'your handler;''_osht_cleanup' EXIT
И это будет правильно обрабатывать кавычки, превращая все между --
и EXIT
в один параметр.
Чтобы привести более сложный пример, я добавляю очистку каталога к обработчику osht, поэтому мой сигнал EXIT
теперь имеет следующее:
trap -- 'rm -fr '\''/var/folders/7d/qthcbjz950775d6vn927lxwh0000gn/T/tmp.CmOubiwq'\'';_osht_cleanup' EXIT
Если вы присвоите это trapDecl
, он будет иметь размер 6 из-за пробелов в обработчике. Таким образом, 'rm
- это один элемент, как и -fr
, вместо 'rm -fr ...'
- как один элемент.
Но currentHandler
получит все три элемента (6 - 3 = 3), и цитирование сработает при запуске eval
.
Аргументы
Аргументы просто пропускают всю часть обработки массива и используют eval
заранее, чтобы получить правильное цитирование. Недостатком является то, что вы заменяете позиционные аргументы в bash, так что это лучше всего сделать из функции. Это код, хотя:
eval "set -- $(trap -p SIGNAL)"
trap -- "your handler${3:+;}${3}" SIGNAL
В первой строке будут установлены позиционные аргументы для вывода trap -p SIGNAL
. Используя пример из раздела Arrays, $1
будет trap
, $2
будет --
, $3
будет _osht_cleanup
(без кавычек!) И $4
будет EXIT
.
Следующая строка довольно проста, кроме ${3:+;}
. Синтаксис ${X:+Y}
означает "output Y
, если переменная X
не установлена или равна нулю" . Таким образом, он расширяется до ;
, если установлено $3
, или ничего другого (если ранее не было обработчика для SIGNAL
).