Подтвердить что ты не робот

Bash: сохранить и восстановить состояние ловушки? Легкий способ управления несколькими обработчиками для ловушек?

Каков хороший способ переопределить обработчики ловушек bash, которые не могут постоянно растоптать существующие, которые могут или не могут быть установлены? Как насчет динамического управления произвольными цепочками ловушек?

Есть ли способ сохранить текущее состояние обработчиков ловушек, чтобы их можно было восстановить позже?

4b9b3361

Ответ 1

Сохранить и восстановить состояние обработчика ловушки в Bash

Я бы представил следующую реализацию стека для отслеживания и восстановления состояния ловушки. Используя этот метод, я могу подталкивать изменения ловушки, а затем удалять их, когда я закончил с ними. Это также можно использовать для объединения многих процедур ловушки вместе.

Смотрите следующий исходный файл (.trap_stack.sh)

#!/bin/bash
trap_stack_name() {
  local sig=${1//[^a-zA-Z0-9]/_}
  echo "__trap_stack_$sig"
}

extract_trap() {
  echo ${@:3:$(($#-3))}
}

get_trap() {
  eval echo $(extract_trap `trap -p $1`)
}

trap_push() {
  local new_trap=$1
  shift
  local sigs=$*
  for sig in $sigs; do
    local stack_name=`trap_stack_name "$sig"`
    local old_trap=$(get_trap $sig)
    eval "${stack_name}"'[${#'"${stack_name}"'[@]}]=$old_trap'
    trap "${new_trap}" "$sig"
  done
}

trap_pop() {
  local sigs=$*
  for sig in $sigs; do
    local stack_name=`trap_stack_name "$sig"`
    local count; eval 'count=${#'"${stack_name}"'[@]}'
    [[ $count -lt 1 ]] && return 127
    local new_trap
    local ref="${stack_name}"'[${#'"${stack_name}"'[@]}-1]'
    local cmd='new_trap=${'"$ref}"; eval $cmd
    trap "${new_trap}" "$sig"
    eval "unset $ref"
  done
}

trap_prepend() {
  local new_trap=$1
  shift
  local sigs=$*
  for sig in $sigs; do
    if [[ -z $(get_trap $sig) ]]; then
      trap_push "$new_trap" "$sig"
    else
      trap_push "$new_trap ; $(get_trap $sig)" "$sig"
    fi
  done
}

trap_append() {
  local new_trap=$1
  shift
  local sigs=$*
  for sig in $sigs; do
    if [[ -z $(get_trap $sig) ]]; then
      trap_push "$new_trap" "$sig"
    else
      trap_push "$(get_trap $sig) ; $new_trap" "$sig"
    fi
  done
}

Это может управлять обработчиками, которые определены как именованные функции, а также ad-hoc-процедуры, определенные как этот пример trap "kill $!" SIGTERM SIGINT.

Это тест script Я использовал, чтобы помочь мне написать его:

#!/bin/bash
source .trap_stack.sh

initial_trap='echo "messy" ;'" echo 'handler'"
non_f_trap='echo "non-function trap"'
f_trap() {
  echo "function trap"
}

print_status() {
  echo "    SIGINT  trap: `get_trap SIGINT`"  
  echo "    SIGTERM trap: `get_trap SIGTERM`"
  echo "-------------"
  echo
}

echo "--- TEST START ---"
echo "Initial trap state (should be empty):"
print_status

echo 'Setting messy non-function handler for SIGINT ("original state")'
trap "$initial_trap" SIGINT
print_status

echo 'Pop empty stacks (still in original state)'
trap_pop SIGINT SIGTERM
print_status

echo 'Push non-function handler for SIGINT'
trap_push "$non_f_trap" SIGINT
print_status

echo 'Append function handler for SIGINT and SIGTERM'
trap_append f_trap SIGINT SIGTERM
print_status

echo 'Prepend function handler for SIGINT and SIGTERM'
trap_prepend f_trap SIGINT SIGTERM
print_status

echo 'Push non-function handler for SIGINT and SIGTERM'
trap_push "$non_f_trap" SIGINT SIGTERM
print_status

echo 'Pop both stacks'
trap_pop SIGINT SIGTERM
print_status

echo 'Prepend function handler for SIGINT and SIGTERM'
trap_prepend f_trap SIGINT SIGTERM
print_status

echo 'Pop both stacks thrice'
trap_pop SIGINT SIGTERM
trap_pop SIGINT SIGTERM
trap_pop SIGINT SIGTERM
print_status

echo 'Push non-function handler for SIGTERM'
trap_push "$non_f_trap" SIGTERM
print_status

echo 'Pop handler state for SIGINT (SIGINT is now back to original state)'
trap_pop SIGINT
print_status

echo 'Pop handler state for SIGTERM (SIGTERM is now back to original state)'
trap_pop SIGTERM
print_status