Skip to content

Instantly share code, notes, and snippets.

@slowpeek
Last active August 20, 2021 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slowpeek/3310c2f09b80d0b2e175122e8c8cae64 to your computer and use it in GitHub Desktop.
Save slowpeek/3310c2f09b80d0b2e175122e8c8cae64 to your computer and use it in GitHub Desktop.
stack.sh
# -*- mode: sh; sh-shell: bash; -*-
# shellcheck shell=bash
# MIT license (c) 2021 https://github.com/slowpeek
# Homepage: https://gist.github.com/slowpeek/3310c2f09b80d0b2e175122e8c8cae64
# bye.sh https://gist.github.com/slowpeek/6127166369d8abd230c30c20cc6a9152
# Simple stack for strings. It operates on var names:
#
# push <var>*
# pop <var>*
#
# 'push' and 'pop' operate on the default stack. 'push_n' and 'pop_n'
# operate on a named stack, the name is passed as the first arg. Names
# are case-insensitive.
#
# If a variable doesnt exist when popping, it would be created as a
# global one.
#
# EXAMPLES
#
# Temporarily change IFS value:
#
# a=(1 2 3)
# push IFS
# IFS=:
# echo "${a[*]}"
# pop IFS
#
# Swap values using a named stack (no reason to use a named stack
# instead of the default one here though):
#
# a=12 b=44
# push_n my1 a b
# pop_n my1 a b
_ () {
unset -f _
declare -g -a ST__STACK=() # Default stack.
declare -g -A ST__NAMED=() # Named stacks registry.
}; _
push () {
while (($# > 0)); do
[[ -v "$1" ]] || bye "Variable ${1@Q} is not set."
ST__STACK+=("${!1}")
shift
done
}
pop () {
while (($# > 0)); do
if [[ ! -v ST__STACK ]]; then
[[ ${ST__POP_EXIT-} == n ]] || bye 'The stack is empty.'
return 1
fi
if [[ $1 == var ]]; then
var=${ST__STACK[-1]}
unset -v 'ST__STACK[-1]'
else
local -n var=$1
# shellcheck disable=SC2034
var=${ST__STACK[-1]}
unset -v 'ST__STACK[-1]'
unset -n var
fi
shift
done
}
push_n () {
local st__name=${1^^}
shift
local -n ST__STACK=ST__STACK_$st__name
if [[ ! -v ST__NAMED["$st__name"] ]]; then
# shellcheck disable=SC2034
ST__NAMED[$st__name]=t
declare -g -a ST__STACK_"$st__name"
ST__STACK=()
fi
push "$@"
}
pop_n () {
local st__name=${1^^}
shift
# shellcheck disable=SC2178
local -n ST__STACK=ST__STACK_"$st__name"
ST__POP_EXIT=n pop "$@" || bye "${st__name@Q} named stack is empty."
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment