Isso funciona em bash (desde o release 4.3) e ksh93 . Para "embasar", substitua todos os typeset por local nas funções e typeset no escopo global por declare (mantendo todas as opções!). Eu sinceramente não sei porque o Bash tem tantos nomes diferentes para coisas que são apenas variações de typeset .
function stack_push
{
typeset -n _stack="$1"
typeset element="$2"
_stack+=("$element")
}
function stack_pop
{
typeset -n _stack="$1"
typeset -n _retvar="$2"
_retvar="${_stack[-1]}"
unset _stack[-1]
}
typeset -a stack=()
stack_push stack "hello"
stack_push stack "world"
stack_pop stack value
printf '%s ' "$value"
stack_pop stack value
printf '%s\n' "$value"
Usando um nameref na função, você evita eval (nunca precisei usar eval em nenhum script!). Fornecendo a função stack_pop com um local para armazenar o valor estourado, você evita a subcamada. Evitando o subshell, a função stack_pop pode modificar o valor da variável stack no escopo externo.
O sublinhado nas variáveis locais na função é evitar ter um nameref que tenha o mesmo nome da variável que ele referencia (Bash não gosta, ksh não se importa, veja esta pergunta ).
Em ksh você pode escrever a função stack_pop como
function stack_pop
{
typeset -n _stack="$1"
printf '%s' "${_stack[-1]}"
unset _stack[-1]
}
E, em seguida, chame-o com
printf '%s %s\n' "${ stack_pop stack }" "${ stack_pop stack }"
( ${ ... } é o mesmo que $( ... ) , mas não cria um subshell)
Mas eu não sou um grande fã disso. IMHO, stack_pop não deveria ter que enviar os dados para stdout, e eu não deveria ter que chamá-lo com ${ ... } para obter os dados. Eu poderia estar mais ok com meu original stack_pop e, em seguida, adicionar um stack_pop_print que faz o acima, se necessário.
Para o Bash, você poderia ir com o stack_pop no começo do meu post, e então ter um stack_top_print que apenas imprime o elemento superior da pilha para stdout, sem removê-lo (o que não pode porque provavelmente seria executado em um sub-diretório $( ... ) .