É possível atribuir shift
ou atribuir um valor a um parâmetro de array de dentro de um subshell?
Código de exemplo:
arr=(a b c)
(shift arr)
echo $arr
# prints: a b c
# should print: b c
Responder1
É o objetivo dos subshells, executar uma parte do código em uma cópia do atualambiente de execução de shell(veja detalhes ema especificação POSIXfor sh
), de modo a preservar o original, portanto, o ponto principal é que qualquer alteração nas variáveis feita no subshell seria perdida após o término do subshell.
Tradicionalmente, isso é feito pelo shell que bifurca um processo e executa o código no filho enquanto o pai aguarda seu encerramento.
O POSIX não exige isso e o ksh93 pelo menos implementa (...)
subshells restaurando cuidadosamente o ambiente original após o retorno do subshell sem bifurcar um processo, se isso puder ser evitado (embora às vezes falhe em fazê-lo corretamente em alguns casos extremos).
zsh
bifurca um processo para isso, como a maioria dos outros shells. Existem exceções para otimização, como quando um (...)
subshell é o último comando em um zsh -c
script:
$ zsh -c 'zmodload zsh/system; echo $$; (echo $sysparams[pid]; ps; ps)'
21085
21085
PID TTY TIME CMD
1839 pts/4 00:00:00 zsh
21085 pts/4 00:00:00 zsh
21086 pts/4 00:00:00 ps
PID TTY TIME CMD
1839 pts/4 00:00:00 zsh
21085 pts/4 00:00:00 ps
É o mesmo processo 21085 acima que executou zsh
, interpretou o subshell e até executou o último ps
comando.
É suficiente definir a trap
para invalidar essa otimização, a questão é que isso só será feito se zsh puder garantir que nada será executado pelo shell após o retorno do subshell.
Para que o processo filho possa alterar o valor de uma variável no processo pai, ele precisaria fazer coisas como anexar gdb
a esse processo e injetar código nele para alterar as estruturas de memória interna desse processo.
Se você quisesse obter o valor de um array conforme definido por um subshell, você precisaria que o subshell passasse sua definição para o pai. Isso poderia ser, por exemplo, através de:
eval "$(
# also a subshell using $(...)
arr=( a b c )
typeset -p arr
)"
Então typeset
será gerado typeset -a arr=( a b c )
(ou typeset -g -a arr=( a b c )
se chamado dentro de uma função), que uma vez eval
uado fará com que a mesma variável seja criada no pai.
A propósito, em vez de:
shift arr
Eu usaria:
shift 1 arr
ou:
arr[1]=()
O shift arr
trecho de código é ambíguo, pois significa coisas diferentes ( shift 1 arr
vs shift arr argv
), dependendo se arr
é declarado como uma variável de array ou não. O uso shift 1 arr
torna mais óbvio que é o primeiro que você deseja.
Responder2
Um subshell é um processo diferente, não pode modificar o processo pai.