保存和恢复陷阱状态?管理多个陷阱处理程序的简单方法?
Posted
技术标签:
【中文标题】保存和恢复陷阱状态?管理多个陷阱处理程序的简单方法?【英文标题】:Save and restore trap state? Easy way to manage multiple handlers for traps? 【发布时间】:2013-04-13 11:14:02 【问题描述】:什么是覆盖bash
陷阱处理程序的好方法,这些处理程序不会永久践踏可能已经设置或尚未设置的现有处理程序?动态管理任意的陷阱例程链怎么样?
有没有办法保存陷阱处理程序的当前状态,以便以后恢复它们?
【问题讨论】:
与您的问题没有直接关系,但bash-preexec 库允许您通过preexec_functions
数组向DEBUG
陷阱注册多个回调。
我的实现:***.com/questions/3338030/…
【参考方案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
这可以管理定义为命名函数的处理程序以及像此示例 trap "kill $!" SIGTERM SIGINT
定义的临时例程。
这是我用来帮我写的测试脚本:
#!/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
【讨论】:
+1 勇敢地回答您自己的问题,并获得相当详尽的解决方案。祝大家好运。 谢谢。我星期五花了很多时间试图弄清楚如何在不诉诸eval
的情况下做到这一点。最后,我从来没有找到一种无需 eval(这也是令人满意的)方法来解析 trap -p
的输出,所以我最终也尝试找到一种方法来分配给动态命名的数组变量。我希望有人有一个等效的 3 线替代品,我们会收到那个人的来信。
抱歉,我不能在星期五的时间里寻找 3 行替代品 ;-),但你不认为关于“从不使用 eval”的炒作有点夸大了?您没有在这些变量中处理用户输入是吗?我认为 eval 和 goto 一样在程序员工具箱中的位置有限。还是您不喜欢它,因为它可能(是?)产生了一个额外的过程?祝大家好运。
我同意“从不使用 eval”经常被视为适用于所有情况的硬性规则。事实是,bash 作为一种语言,有一些缺点,只需要 eval 作为一种解决方法。一个人应该始终仔细检查他们向eval
提供的内容,但你不能总是完全避免它。
有趣。我的陷阱通常类似于trap 'rm -f $tmp.?; exit 1'
0 1 2 3 13 15`,其中$tmp
是脚本中用于临时文件的基本名称。由于该陷阱中的exit
,您无法有意义地附加到它(不是我能想到很多我想要的地方),但很明显,您的“前置”选项在这种情况下有效。所以,也许这对于我使用trap
处理的问题来说只是矫枉过正,但它是 shell 编程中的绝技。以上是关于保存和恢复陷阱状态?管理多个陷阱处理程序的简单方法?的主要内容,如果未能解决你的问题,请参考以下文章