Skip to content

Commit

Permalink
upload
Browse files Browse the repository at this point in the history
  • Loading branch information
dsx724 committed May 8, 2022
1 parent bcb80e4 commit 55dc5c7
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 2 deletions.
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,23 @@
# bash-trap-stack
command stack for bash traps
# Bash Trap Stack
## Purpose
The traps.sh shell script allows you to create a stack of commands to execute for trap.
## Commands
* traps_start - registers the exit trap
* traps_push $@ - pushes $@ as one entry to the stack
* traps_pop - pops one entry from the stack and execute
* traps_drop - pops one entry from the stack and do nothing
* traps_isEmpty - returns 0 if empty, returns 1 if not empty
* traps_stop - unregisters the exit trap if there is nothing on the stack
* traps_cancel - unregisters the exit trap and remove all entries from the stack
* traps_exit - unregisters the exit map and pops all entries from the stack
* traps_diag - print the stack on pipe 1
## User Variables
* TRAPS_DEBUG=0 - provides more verbose output on pipe 2
* TRAPS_SIGNAL=EXIT - controls the trap signal
## Typical Sequence
* traps_start
* traps_push echo "test"
* traps_pop
* traps_stop
## Notes
You can use *set -eE* along with *TRAPS_SIGNAL=ERR* before you start the trap stack to get the function and line number that triggered the trap.
52 changes: 52 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash

# SPDX-License-Identifier: MIT
# Copyright (C) 2022 Da Xue

. traps.sh

TRAPS_DEBUG=1

function traps_test {
traps_start
traps_push "echo" "traps 1" "test 1" "drop"
traps_push "echo" "traps 2" "test 2" "pop"
traps_push "echo" "traps 3" "test 3" "drop"
traps_push "echo" "traps 2" "test 2" "pop"
traps_diag
echo
traps_isEmpty && echo "Empty" || echo "Not Empty"
echo
traps_drop
traps_diag
echo
traps_pop
traps_diag
echo
traps_drop
traps_diag
echo
traps_pop
traps_diag
echo
traps_stop
echo
traps_start
traps_cancel
echo
traps_pop && echo "FAILED" || true
traps_diag
echo
traps_cancel && echo "FAILED" || true
traps_diag
echo
set -eE
TRAPS_SIGNAL=ERR
traps_start
traps_push echo "test"
false
}

if [ "${BASH_SOURCE[0]##*/}" = "${0##*/}" ]; then
traps_test
fi
149 changes: 149 additions & 0 deletions traps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#!/bin/bash

# SPDX-License-Identifier: MIT
# Copyright (C) 2022 Da Xue

TRAPS_DEBUG=0
TRAPS_SIGNAL=EXIT

declare -a TRAPS_PARAMS
declare -a TRAPS_LENGTHS
TRAPS_LENGTH=

function traps_start {
if [ -z "$TRAPS_LENGTH" ]; then
TRAPS_LENGTH=0
if [ "$TRAPS_SIGNAL" = "ERR" ]; then
trap 'traps_exit "$FUNCNAME" "$LINENO"' $TRAPS_SIGNAL
else
trap traps_exit $TRAPS_SIGNAL
fi
else
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: duplicate call" >&2
fi
return 1
fi
}

function traps_isEmpty {
if [ -z "$TRAPS_LENGTH" ]; then
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps not started" >&2
fi
return 2
fi
if [ $TRAPS_LENGTH -gt 0 ]; then
return 1
fi
return 0
}

function traps_push {
if [ -z "$TRAPS_LENGTH" ]; then
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps not started" >&2
fi
return 1
fi
TRAPS_PARAMS+=("$@")
TRAPS_LENGTHS+=($#)
((TRAPS_LENGTH=TRAPS_LENGTH+1))
}

function traps_pop {
if [ -z "$TRAPS_LENGTH" ]; then
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps not started" >&2
fi
return 1
elif [ $TRAPS_LENGTH -gt 0 ]; then
local trap_length=${TRAPS_LENGTHS[@]: -1}
local trap_cmd=(${TRAPS_PARAMS[@]: -$trap_length})
local traps_params_end=$((${#TRAPS_PARAMS[@]}-trap_length))
TRAPS_PARAMS=("${TRAPS_PARAMS[@]:0:$traps_params_end}")
TRAPS_LENGTH=$((TRAPS_LENGTH-1))
TRAPS_LENGTHS=(${TRAPS_LENGTHS[@]:0:$TRAPS_LENGTH})
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: ${trap_cmd[@]}" >&2
fi
"${trap_cmd[@]}"
else
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps empty" >&2
fi
return 1
fi
}

function traps_drop {
if [ -z "$TRAPS_LENGTH" ]; then
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps not started" >&2
fi
return 1
elif [ $TRAPS_LENGTH -gt 0 ]; then
local trap_length=${TRAPS_LENGTHS[@]: -1}
local traps_params_end=$((${#TRAPS_PARAMS[@]}-trap_length))
TRAPS_PARAMS=("${TRAPS_PARAMS[@]:0:$traps_params_end}")
TRAPS_LENGTH=$((TRAPS_LENGTH-1))
TRAPS_LENGTHS=(${TRAPS_LENGTHS[@]:0:$TRAPS_LENGTH})
else
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps empty" >&2
fi
return 1
fi
}


function traps_stop {
if [ "$TRAPS_LENGTH" = "0" ]; then
TRAPS_LENGTH=
trap - $TRAPS_SIGNAL
else
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: registered traps" >&2
traps_diag >&2
fi
return 1
fi
}

function traps_cancel {
if [ -z "$TRAPS_LENGTH" ]; then
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps not started" >&2
fi
return 1
fi
TRAPS_PARAMS=()
TRAPS_LENGTHS=()
TRAPS_LENGTH=
trap - $TRAPS_SIGNAL
}

function traps_exit {
if [ "$TRAPS_DEBUG" -eq 1 ]; then
if [ "$TRAPS_SIGNAL" = "ERR" ]; then
echo "$FUNCNAME: $TRAPS_SIGNAL IN $1 LINE $2" >&2
fi
fi
trap - $TRAPS_SIGNAL
if [ -z "$TRAPS_LENGTH" ]; then
if [ "$TRAPS_DEBUG" -eq 1 ]; then
echo "$FUNCNAME: traps not initiated" >&2
fi
return 1
fi
while [ "$TRAPS_LENGTH" -gt 0 ]; do
traps_pop
done
return 1
}

function traps_diag {
echo "$FUNCNAME params: ${TRAPS_PARAMS[@]}"
echo "$FUNCNAME lengths: ${TRAPS_LENGTHS[@]}"
echo "$FUNCNAME length: $TRAPS_LENGTH"
}

0 comments on commit 55dc5c7

Please sign in to comment.