$ () É um subshell?

51

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.

leeand00
fonte
4
Possível duplicata de O que é substituição de comando em um shell?
Julien Lopez #

Respostas:

75

$(…)é 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:

  • Subshell para agrupamento : ( … )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.
  • Pipeline : … | …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 lastpipeopção configurada e efetiva), o lado direito é executado no shell original, portanto, a construção do pipeline cria apenas um subshell.
  • Substituição de comando : $(…)(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.)
  • Substituição de processo : <(…)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.
  • Coprocesso : 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.

¹ Em vez de executar um shell separado .

Gilles 'SO- parar de ser mau'
fonte
Você também pode incluir ${...}na resposta?
User1717828
3
@ user1717828 O que? Por quê? O que a expansão variável remotamente tem a ver com essa pergunta? Não vou incluir todo o manual do shell na minha resposta.
Gilles 'SO- stop be evil'
11
O que a expansão variável remotamente tem a ver com essa pergunta? Não sei, foi por isso que perguntei :-) Então, acho que a substituição da chave não é como a substituição da chave entre parênteses.
User1717828
@ user1717828: a expansão variável não está relacionada aos subshells; é um mecanismo completamente separado, e definitivamente vale a pena ler se você está apenas começando!
0xdd
11
@EnricoMariaDeAngelis Não é o único caminho, mas é o caminho mais natural. Outra maneira é command | { read line; … }(dependendo do shell, ainda linepode 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.
Gilles 'SO- stop be evil'
20

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 commandem um ambiente subshell [...]

Ignacio Vazquez-Abrams
fonte
9
Isso também é especificado explicitamente pelo POSIX .
Stephen Kitt
11
Curiosamente, no CentOS 7, a página de bashmanual 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.
dr01
6
@ dr01 Pelo contrário, o bash 4.4 mudou a redação dessa frase para incluir a palavra “subshell”. Foi um esclarecimento: o manual mencionou explicitamente que várias outras construções eram subcamadas, mas até o 4.4 não era explicitamente indicado para substituição de comando.
Gilles 'SO- stop be evil'
Sim, no CentOS v7.4.1708 (relativamente recente) o bash é a v4.2.46.
Dr01
5

Sim, ( commands... )é um bashsubshell que será executado commands...em outro processo.

A única diferença que você tem $( commands... )é que essa parte do código será commands...substituída , após a execução, por tudo o que você commands...escreveu stdout.

Iskustvo
fonte