Resposta curta
O comando executado por eval
é executado no shell atual e o comando canalizado para bash
é executado em um sub-shell, por exemplo:
> echo 'x=42' | bash; echo $x
> eval 'x=42'; echo $x
42
Resposta mais longa
Nos comentários foi feita a alegação de que nas versões mais recentes de bash
(> = 4,2) o primeiro comando também poderia ter o mesmo efeito. No entanto, este não parece ser o caso.
Na verdade, existem alguns fatores que fazem com que o comando canalizado não seja executado na sessão atual: o pipe e o comando bash
.
Na maior parte, os comandos canalizados são executados em subshells. O manual do bash ( seção 3.2.2: pipelines ) tem o seguinte para dizer:
Each command in a pipeline is executed in its own subshell (see Command Execution Environment).
Como apontado nos comentários, esse comportamento pode ser modificado por meio da opção lastpipe
. O Manual do Bash ( Seção 4.3.2: O Shopt Builtin ) o seguinte para falar sobre a opção lastpipe
:
lastpipe
If set, and job control is not active, the shell runs the last command of a pipeline not executed in the background in the current shell environment.
Podemos verificar que este é o caso da seguinte forma:
Primeiro, ative o lastpipe
:
> shopt -s lastpipe
Em seguida, desabilite o controle de trabalho:
> set +m
Agora, execute um comando que defina uma variável dentro de um canal:
> unset x
> echo x=42 | while IFS= read -r line; do eval "${line}"; done;
> echo $x
42
Observe que usamos o comando while
e read
como solução alternativa, pois o comando eval
não pode ler sua entrada de stdin (portanto, não é possível obter sua entrada de um canal).
Este exemplo demonstra que o comando mais à direita no pipe pode, de fato, ser executado no shell atual. No entanto, isso não afeta realmente nosso exemplo original. Mesmo com lastpipe
habilitado e controle de trabalho desabilitado, ainda obtemos o seguinte resultado ao canalizar para bash
:
> echo 'x=42' | bash; echo $x
>
Isso ocorre porque o próprio comando bash
executa sua entrada em um subshell.