Eu entendo a sintaxe do subshell (<commands...>)
, é $()
apenas um subshell do qual você pode recuperar valores variáveis?
Nota: Isso se aplica ao bash 4.4 com base em palavras diferentes na documentação.
Eu entendo a sintaxe do subshell (<commands...>)
, é $()
apenas um subshell do qual você pode recuperar valores variáveis?
Nota: Isso se aplica ao bash 4.4 com base em palavras diferentes na documentação.
Respostas:
$(…)
é um subshell por definição: é uma cópia do estado de tempo de execução do shell¹, e as alterações no estado feito no subshell não têm impacto no pai. Um subshell é tipicamente implementado bifurcando um novo processo (mas alguns shells podem otimizar isso em alguns casos).
Não é um subshell do qual você pode recuperar valores variáveis. Se as alterações nas variáveis tivessem um impacto sobre o pai, não seria um subshell. É um subshell cuja saída o pai pode recuperar. O subshell criado por $(…)
tem sua saída padrão definida como um canal, e o pai lê esse canal e coleta a saída.
Existem várias outras construções que criam um subshell. Eu acho que esta é a lista completa do bash:
( … )
não faz nada além de criar um subshell e aguarde o término). Contraste com o { … }
qual os grupos comandam puramente para fins sintáticos e não cria um subshell.… &
Segundo plano : cria um subshell e não espera que ele termine.… | …
cria dois subshells, um para o lado esquerdo e outro para o lado direito, e aguarda o término de ambos. O invólucro cria um tubo e conecta a saída padrão do lado esquerdo à extremidade de gravação do tubo e a entrada padrão do lado direito à extremidade de leitura. Em alguns shells (ksh88, ksh93, zsh, bash com a lastpipe
opção configurada e efetiva), o lado direito é executado no shell original, portanto, a construção do pipeline cria apenas um subshell.$(…)
(também escrito `…`
) cria um subshell com sua saída padrão definida como um pipe, coleta a saída no pai e expande para essa saída, menos suas novas linhas finais. (E a saída pode estar ainda mais sujeita a divisão e globbing, mas isso é outra história.)<(…)
cria um subshell com sua saída padrão definida como um pipe e se expande para o nome do pipe. O pai (ou algum outro processo) pode abrir o canal para se comunicar com o subshell. >(…)
faz o mesmo, mas com o tubo na entrada padrão.coproc …
cria um subshell e não espera que ele seja finalizado. A entrada e saída padrão do subshell são definidas para um tubo com o pai conectado à outra extremidade de cada tubo.${...}
na resposta?
command | { read line; … }
(dependendo do shell, ainda line
pode ou não estar disponível após o pipeline). Todas as formas envolvem um subshell porque o comando que produz a saída precisa ser executado independentemente do shell que lê a entrada. Se o comando for puramente interno ao shell (apenas construções e componentes do shell, sem comandos externos), o shell pode não criar um subprocesso, mas isso é apenas uma otimização, mas ainda cria um subshell.
Na página do manual bash (1) na versão bash 4.4, seção "EXPANSÃO", subseção "Substituição de Comando":
Bash realiza a expansão executando
command
em um ambiente subshell [...]
bash
manual não menciona nenhum subconjunto: Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.
eu me pergunto se isso foi uma omissão deliberada.