可变膨胀的Bash陷阱?

时间:2017-10-13 16:57:25

标签: bash

根据我不允许评论的这个问题:

Is it necessary to specify traps other than EXIT?

恕我直言,这是一个不完整的答案,因为它没有涵盖通常的案例:

TEMPDIR_OR_FILE=$(mktemp [ some switches and params and an XXX pattern] )
# ...so we want trap to do rm -rf ${TEMPDIR_OR_FILE}

给出的例子是:

# reset
trap 'excode=$?; cmd; trap - EXIT; echo $excode' EXIT HUP INT QUIT PIPE TERM

# ignore
trap 'excode=$?; trap "" EXIT; cmd; echo $excode' EXIT HUP INT QUIT PIPE TERM

此处的问题是,单引号会阻止您展开${TEMPDIR_OR_FILE}

我认为这是一个复杂因素是变量扩展的时间。我需要立即扩展${TEMPDIR_OR_FILE},但其他项可能需要等到陷阱执行。我该如何工作?

1 个答案:

答案 0 :(得分:1)

最佳实践:在执行时间扩展

简单案例

你担心的代码,

trap 'EXIT' 'rm -f "$TEMPDIR_OR_FILE"'

... 确实有效;它只是在陷阱运行时查找TEMPDIR_OR_FILE,而不是在它被定义时查找。这没有什么不妥:当陷阱运行时,最好时间来查看您的临时文件定义,因为这样您的脚本的其余部分可以在其中适当地更改这些定义执行。

获得幻想:处理任意数量的临时文件

请考虑以下事项:

declare -A tempfiles=( )
cleanup() { (( ${#tempfiles[@]} )) && rm -rf -- "${!tempfiles[@]}"; }
trap 'cleanup' EXIT

# ...do some stuff...
tempfiles[something]=$(mktemp -t -d something.XXXXXX)
echo "hello" >"${tempfiles[something]}/greeting"

# ...do more stuff...
tempfiles[something_else]=$(mktemp -t something_else.XXXXXX)
if [[ $keep_something_else ]]; then
  # the user wants us to keep this temporary file! remove it from deletion list
  unset tempfiles[keep_something_else]
fi

通过上述内容,您只需将清理功能定义为,并且当时不需要知道您的临时目录;当您退出时,您将查找列表,因为它存在然后

字面答案:在定义时间扩展

在大多数情况下,在执行陷阱时,与在其定义时相比,扩展变量是合乎需要的。但是,你要求以另一种方式去做。

要安全地执行此操作 ,请使用printf %q生成文件名的eval - 安全版本,并在定义陷阱时将其展开为双引号。

printf -v tempdir_or_file_q '%q' "$TEMPDIR_OR_FILE"
trap 'retval=$?; rm -rf '"${tempdir_or_file_q}"'; exit "$retval"'

请注意,在引用要在定义时扩展的变量之前,我们结束初始单引号,用双引号展开它,结束那些双引号并在之后切换回单引号。