bash: improve prior_trap processing (#5142)

We use `trap` to bootstrap our installation function (__bp_install). We
remove our code upon first execution but need to restore any preexisting
trap calls. We previously used `sed` to process the trap string, but
that had two downsides:

1. `sed` is an external command dependency. It needs to exist on the
system, and we need to invoke it in a subshell (which has some runtime
cost).
2. The regular expression pattern was imperfect and didn't handle
trickier cases like `'` characters in the trap string:

        $ (trap "echo 'hello'" DEBUG; trap -p DEBUG)
        hello
        trap -- 'echo '\''hello'\''' DEBUG

This change removes the dependency on `sed` by locally evaluating the
trap string and extracting any prior trap. This works reliably because
we control the format our trap string, which looks like this (with
newlines expanded):

    __bp_trap_string="$(trap -p DEBUG)"
    trap - DEBUG
    __bp_install

Upstream: https://github.com/rcaloras/bash-preexec/pull/170
This commit is contained in:
Mitchell Hashimoto
2025-01-16 13:04:57 -08:00
committed by GitHub

View File

@ -295,10 +295,8 @@ __bp_install() {
trap '__bp_preexec_invoke_exec "$_"' DEBUG trap '__bp_preexec_invoke_exec "$_"' DEBUG
# Preserve any prior DEBUG trap as a preexec function # Preserve any prior DEBUG trap as a preexec function
local prior_trap eval "local trap_argv=(${__bp_trap_string:-})"
# we can't easily do this with variable expansion. Leaving as sed command. local prior_trap=${trap_argv[2]:-}
# shellcheck disable=SC2001
prior_trap=$(sed "s/[^']*'\(.*\)'[^']*/\1/" <<<"${__bp_trap_string:-}")
unset __bp_trap_string unset __bp_trap_string
if [[ -n "$prior_trap" ]]; then if [[ -n "$prior_trap" ]]; then
eval '__bp_original_debug_trap() { eval '__bp_original_debug_trap() {