O primeiro erro aqui está em pensar que o shell apenas executa fork()
para executar um comando externo e que a descrição de fork()
é, portanto, uma descrição da operação do shell. Na realidade, tanto o processo pai quanto o filho fazem um monte de coisas adicionais. E, em particular, a criança chama execve()
para executar o comando externo.
Neste ponto, a partir da leitura da página de manual para execve()
, a luz deve estar amanhecendo. Um dos parâmetros para a chamada do sistema é o ambiente que a imagem do processo sobreposto terá na inicialização do programa. Obviamente, não há mágica sob o ambiente passando pelo sistema operacional. O shell tem que inventar explicitamente um ambiente e passá-lo para execvce()
no processo filho. Esse ambiente pode ser o que a casca quiser.
O que nos leva ao segundo erro. Variáveis de ambiente não são variáveis de shell. Quando o programa shell é inicializado, ele importa as variáveis de ambiente para as variáveis do shell com os mesmos nomes (e em um shell, nas funções do shell). Quando se trata de gerar um comando externo, ele exporta as variáveis do shell para o (novo) ambiente que ele cria e passa para o kernel em execve()
. Entre whiles, tudo o que você faz em scripts e interativamente com variáveis shell afeta essas variáveis, que são distintas do ambiente do processo shell. (O ambiente do processo de shell geralmente permanece intocado e não é usado após a importação na inicialização do programa.)
Qual - Ei, pronto! - explica por que o shell export
embutido é chamado de "exportação".
E que também explica como os recursos internos, como set
, veem variáveis não exportadas. Eles não envolvem a sobreposição do programa shell com outro programa, e não envolvem a configuração de um novo ambiente para passar para execve()
. Da mesma forma, a criação de subshells com parênteses não envolve, por si só, execve()
e, portanto, não envolve a exportação de variáveis do shell para criar um ambiente.