eval
e exec
são ambos comandos internos do bash (1) que executam comandos.
Também vejo exec
algumas opções, mas essa é a única diferença? O que acontece com o contexto deles?
bash
shell
shell-builtin
Willian Paixao
fonte
fonte
Respostas:
eval
eexec
são bestas completamente diferentes. (Além do fato de que ambos executarão comandos, tudo o que você faz em um shell também).O que
exec cmd
faz é exatamente o mesmo que apenas executarcmd
, exceto que o shell atual é substituído pelo comando, em vez de um processo separado estar sendo executado. Internamente, executar o say/bin/ls
chamaráfork()
para criar um processo filho e,exec()
em seguida, executar o filho/bin/ls
.exec /bin/ls
por outro lado, não bifurca, mas apenas substitui a concha.Comparar:
com
echo $$
imprime o PID do shell que iniciei e a listagem/proc/self
nos fornece o PID dols
que foi executado a partir do shell. Geralmente, os IDs de processo são diferentes, mas comexec
o shell els
têm o mesmo ID de processo. Além disso, o comando a seguirexec
não foi executado, pois o shell foi substituído.Por outro lado:
eval
executará os argumentos como um comando no shell atual. Em outras palavras,eval foo bar
é o mesmo que justofoo bar
. Mas as variáveis serão expandidas antes da execução, para que possamos executar comandos salvos nas variáveis do shell:Como não criará um processo filho, a variável é definida no shell atual. (É claro
eval /bin/ls
que criará um processo filho, da mesma maneira que um velho comum/bin/ls
faria.)Ou podemos ter um comando que produz comandos shell. A execução
ssh-agent
inicia o agente em segundo plano e gera várias atribuições de variáveis, que podem ser definidas no shell atual e usadas pelos processos filhos (osssh
comandos que você executaria). Portanto,ssh-agent
pode ser iniciado com:E o shell atual obterá as variáveis para outros comandos herdarem.
Obviamente, se a variável
cmd
contiver algo comorm -rf $HOME
, executareval "$cmd"
não seria algo que você gostaria de fazer. Mesmo coisas como substituições de comando dentro da corda seria processado, por isso deve-se realmente ter certeza de que a entrada paraeval
é seguro antes de o utilizar.Muitas vezes, é possível evitar
eval
e evitar a mistura acidental de código e dados da maneira errada.fonte
eval
em primeiro lugar a esta resposta também. Coisas como variáveis de modificação indireta podem ser feitas em muitos shells através dedeclare
/typeset
/nameref
e expansões como${!var}
, então eu os usaria em vez de, aeval
menos que realmente tivesse que evitá-lo.exec
não cria um novo processo. Ele substitui o processo atual pelo novo comando. Se você fez isso na linha de comando, ele efetivamente encerrará sua sessão do shell (e talvez você faça logout ou feche a janela do terminal!)por exemplo
Aqui estou
ksh
(minha concha normal). Eu começobash
e depois dentro do bashexec /bin/echo
. Podemos ver que fui devolvidoksh
depois porque obash
processo foi substituído por/bin/echo
.fonte
TL; DR
exec
é usado para substituir o processo atual do shell por novos e manipular descritores de redirecionamento / arquivo de fluxo, se nenhum comando foi especificado.eval
é usado para avaliar seqüências de caracteres como comandos. Ambos podem ser usados para criar e executar um comando com argumentos conhecidos em tempo de execução, masexec
substituem o processo do shell atual, além de executar comandos.exec buil-in
Sintaxe:
De acordo com o manual, se houver um comando especificado, este built-in
Em outras palavras, se você estava executando
bash
com o PID 1234 e se executavaexec top -u root
nesse shell, otop
comando terá o PID 1234 e substituirá o processo do shell.Onde isso é útil? Em algo conhecido como scripts de wrapper. Esses scripts constroem conjuntos de argumentos ou tomam certas decisões sobre quais variáveis passar para o ambiente e, em seguida, usam-se
exec
para substituir a si mesmo por qualquer comando especificado e, é claro, fornecendo os mesmos argumentos que o script do wrapper criou ao longo do caminho.O que o manual também afirma é que:
Isso nos permite redirecionar qualquer coisa dos fluxos de saída dos shells atuais para um arquivo. Isso pode ser útil para fins de registro ou filtragem, onde você não deseja ver
stdout
apenas os comandosstderr
. Por exemplo, assim:Esse comportamento o torna útil para fazer logon em scripts de shell , redirecionar fluxos para separar arquivos ou processos e outras coisas divertidas com descritores de arquivo.
No nível do código-fonte, pelo menos para a
bash
versão 4.3, oexec
interno é definido embuiltins/exec.def
. Ele analisa os comandos recebidos e, se houver algum, passa as coisas para ashell_execve()
função definida noexecute_cmd.c
arquivo.Para encurtar a história, existe uma família de
exec
comandos na linguagem de programação C eshell_execve()
é basicamente uma função de wrapper deexecve
:avaliação interna
O manual do bash 4.3 afirma (ênfase adicionada por mim):
Observe que não há substituição do processo. Diferentemente de
exec
onde o objetivo é simular aexecve()
funcionalidade, oeval
built-in serve apenas para "avaliar" argumentos, como se o usuário os tivesse digitado na linha de comando. Como tal, novos processos são criados.Onde isso pode ser útil? Como Gilles apontou nesta resposta , "... eval não é usado com muita frequência. Em algumas conchas, o uso mais comum é obter o valor de uma variável cujo nome não é conhecido até o tempo de execução". Pessoalmente, eu o usei em alguns scripts no Ubuntu, onde era necessário executar / avaliar um comando com base no espaço de trabalho específico que o usuário estava usando no momento.
No nível do código-fonte, ele é definido
builtins/eval.def
e passa a sequência de entrada analisada paraevalstring()
funcionar.Entre outras coisas,
eval
pode atribuir variáveis que permanecem no ambiente de execução de shell atual, enquantoexec
não pode:fonte
Uh o quê? O ponto principal
eval
é que ele não cria de forma alguma um processo filho. Se eu fizerem um shell, depois o shell atual terá mudado de diretório. Nem
exec
cria um novo processo filho; em vez disso, altera o executável atual (ou seja, o shell) para o determinado; a identificação do processo (e arquivos abertos e outras coisas) permanecem os mesmos. Ao contrárioeval
, umexec
não retornará ao shell de chamada, a menos que oexec
próprio falhe devido à incapacidade de encontrar ou carregar o executável ou morrer devido a problemas de expansão de argumento.eval
basicamente interpreta seus argumentos como uma sequência após concatenação, ou seja, ele fará uma camada extra de expansão de curinga e divisão de argumentos.exec
não faz nada assim.fonte
Avaliação
Estes trabalhos:
No entanto, estes não:
Substituição da imagem do processo
Este exemplo demonstra como
exec
substitui a imagem do seu processo de chamada:Observe que foi
exec echo $$
executado com o PID do subshell! Além disso, depois de concluído, estávamos de volta ao nossosh$
shell original .Por outro lado,
eval
se não substituir a imagem do processo. Em vez disso, ele executa o comando fornecido, como faria normalmente dentro do próprio shell. (Obviamente, se você executar um comando que exige que um processo seja gerado ... isso é exatamente o que acontece!)fonte
exec
)