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 $( ... )
.