Quando executo um executável (como a.out) de um shell Bash, esse executável é executado em algum tipo de "sub" shell, ou seja, diferente do shell no qual estou digitando?
Vou tentar ilustrar minha pergunta com um exemplo. O programa a seguir obtém e imprime o valor de uma variável de ambiente, altera-o e, em seguida, obtém e imprime novamente:
#include <iostream>
#include <string>
#include <cstdlib>
int main( int argc, char* argv[] )
{
std::string str( getenv( "FOO" ) );
std::cout << str << std::endl;
setenv( "FOO", "bar", 1 );
str = getenv( "FOO" );
std::cout << str << std::endl;
return 0;
}
Agora, observe a saída quando executo o seguinte no meu prompt do Bash:
>unset FOO && export FOO=foo && printf "$FOO\n" && ./a.out && printf "$FOO\n"
foo
foo
bar
foo
>
>unset FOO && export FOO=baz && printf "$FOO\n" && ./a.out && printf "$FOO\n"
baz
baz
bar
baz
Portanto, estou exportando FOO
para que seja obtido a partir do executável - entendo isso. E a saída do executável mostra o envvar sendo alterado.
Mas o final printf "$FOO\n"
imprime o valor pré-executável. Isso ocorre porque o executável é executado em um "ambiente diferente" daquele em que digito comandos?
No Unix, cada processo tem sua própria cópia independente do ambiente. Um processo obtém seu ambiente inicial quando é criado (via
fork()
) copiando o ambiente do processo pai.Portanto, se você adicionar uma variável ao ambiente do shell antes de chamar a.out, a.out a verá (porque a.out recebeu uma cópia do ambiente do shell, que continha essa variável).
Se a.out muda o ambiente, isso muda o ambiente de a.out — não o do shell. Se a.out chamasse outro programa (por exemplo, usando
system()
), esse programa veria o ambiente alterado, porque obteria uma cópia do ambiente de a.out.Quando a.out sai, suas variáveis de ambiente são destruídas; é claro que, se um processo filho estivesse em execução, ele ainda manteria sua cópia (até sair).
Se você modificar o ambiente no shell, enquanto a.out ainda estiver em execução (por exemplo, em segundo plano:
a.out &
), então a.out não verá as alterações: o ambiente é copiado apenas na criação do processo.[Observe que esta é a maneira típica; a
execve
syscall permite executar um programa com um ambiente especificado por você, em vez daquele copiado do processo pai.]