Skip to content

Instantly share code, notes, and snippets.

@Lucretiel
Last active April 6, 2022 02:53
Show Gist options
  • Save Lucretiel/c1094aad1572571c349ae3266d173b35 to your computer and use it in GitHub Desktop.
Save Lucretiel/c1094aad1572571c349ae3266d173b35 to your computer and use it in GitHub Desktop.
Trap a command in bash without removing the previous trap command
#!/bin/bash
# This function adds an additional command to the trap stack. Each command
# added in this way will be called in reverse order when the signal is received.
#
# This function works with a simple concatenation with the currently existing
# trap function. Popping something from the trap stack without running it is
# left as an exercise to the reader; it requires at least a parser capable of
# matching { } correctly.
#
# Usage: `add_trap <COMMAND> <SIGNAL>`
#
# THIS FUNCTION DOES NOT SUPPORT MUTLILINE COMMANDS OR COMMANDS WITH ANY
# SINGLE QUOTES, EVEN IF THEY'RE ESCAPED, SO DON'T TRY IT
add_trap() {
# Check for --help
for arg in "$@"
do
case "$arg" in
'-h' | '--help' )
echo "Usage: add_trap <COMMAND> <REASON>"
echo
echo "Push a COMMAND on to the trap stack; this COMMAND will be run before and in addition to any other current trap commands for the given REASON"
return 0
esac
done
# Check number of arguments
if test "$#" -gt 2
then
{
echo "Error: more than two argument given. Did you forget to enclose your COMMAND in quotes?"
echo
echo "Usage: add_trap <COMMAND> <REASON>"
} >&2
return 1
fi
# Strip trailing whitespace and semicolons from the command
COMMAND="$(echo "$1" | sed -e 's/^\(.*[^;\s]\)[; ]*$/\1/g')"
TRAP="$2"
# Test that we have a command
if test -z "$COMMAND"
then
{
echo "Error: need a command to trap with"
echo
echo "Usage: add_trap <COMMAND> <REASON>"
} >&2
return 1
fi
# Test that we have a signal or reason to trap on
if test -z "$TRAP"
then
{
echo "Error: need a signal or other reason to trap on (such as EXIT or SIGINT)"
echo
echo "Usage: add_trap <COMMAND> <REASON>"
} >&2
return 1
fi
# Check no single quotes in $COMMAND
if echo "$COMMAND" | grep -q "'"
then
echo "can't add commands with single quote characters"
return 1
fi
# TODO: detect and reject multiline commands
CURRENT_TRAP="$(trap -p "$TRAP" | grep -o -P "(?<=-- ').*(?=' EXIT)")"
trap "{ $COMMAND ; } ; $CURRENT_TRAP" "$TRAP"
}
# Same as above, but without correctness checking
add_trap_unchecked() {
COMMAND="$1"
TRAP="$2"
CURRENT_TRAP="$(trap -p "$TRAP" | grep -o -P "(?<=-- ').*(?=' EXIT)")"
trap "{ $COMMAND ; } ; $CURRENT_TRAP" "$TRAP"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment