Por que as variáveis não ambientais são passadas para a subshell invocada pela substituição de comandos?

0

O manual do Bash diz:

Command substitution, commands grouped with parentheses, and asynchronous commands are invoked in a subshell environment that is a duplicate of the shell environment, except that traps caught by the shell are reset to the values that the shell inherited from its parent at invocation.

Neste exemplo, b não é uma variável de ambiente, portanto, b não existe na subzela criada pela substituição de comando. Então, por que c está atribuído o valor de b pela substituição do comando? É porque a expansão de parâmetro acontece por $b no processo do shell antes de criar um subshell para executar echo 1 ?

$ b=1
$ c=$(echo $b)
$ echo $c
1
    
por Tim 11.02.2016 / 02:58

3 respostas

6

Não, o subshell foi criado primeiro.

Um ambiente de execução de shell contém parâmetros de shell definidos por atribuições de variáveis e variáveis de ambiente. Um ambiente subshell foi criado duplicando o ambiente shell, portanto, ele contém todas as variáveis do ambiente shell atual.

Veja o exemplo:

$ b=1
$ c=$(b=2; echo "$b")
$ echo "$c"
2

A saída é 2 em vez de 1 .

Um ambiente subshell criado por substituição de comando é diferente com um ambiente de shell criado chamando o executável do shell.

Quando você chama o shell como:

$ bash -c :

o shell atual usou execve () para criar um novo processo shell, algo como:

execve("/bin/bash", ["bash", "-c", ":"], [/* 64 vars */]) = 0

o último argumento passado para execve contém todas as variáveis de ambiente.

É por isso que você precisa exportar as variáveis para empurrá-lo para as variáveis de ambiente , que será incluído nos comandos executados posteriormente:

$ a=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++

Observe que as variáveis de ambiente mudam de 64 para 65. E as variáveis que não são exportadas não serão passadas para o novo ambiente de shell:

$ a=; b=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++

Observe que as variáveis de ambiente ainda são 65.

Na substituição do comando, o shell usou fork () para criar um novo processo shell, que apenas copiou o ambiente atual do shell - que contém variáveis configuradas e variáveis de ambiente.

    
por 11.02.2016 / 03:31
3

Sim b não é uma variável de ambiente.
Mas: Sim, b existe no subnível criado pela substituição de comandos:

$ b=11; c="$(echo $b)"; echo "$c"          ### b exists in subshell.
11
$ b=11; c="$(b=33; echo $b)"; echo "$c"    ### $b is not replaced before
33                                         ### the subshell is executed.

O que não recebe as variáveis é um "processo filho completo" :

$ b=11; bash -c 'echo "<$b>"'              ### b does not exist.
<>
$ b=11 bash -c 'echo "<$b>"'               ### environment b.
<11> 

Só que um processo pode receber variáveis no ambiente, é claro.

Última linha em SubShell do Wooledge :

In the subshell, the regular shell variable a is visible; but because it is not exported, the full child process does not see it.

    
por 11.02.2016 / 05:20
2

A substituição de comandos causa uma chamada normal para o interpretador de shell e este interpretará o comando echo em sub-process .

O sub-process é necessário, pois o shell precisa estabelecer um pipe para o comando echo para poder ler os resultados.

O sub-process que executa o comando echo é criado por fork() e isso cria cópias de todas as variáveis do processo principal do shell. É por isso que $b é acessível pelo comando echo .

    
por 11.02.2016 / 12:21

Tags