Eu estava lendo um script que alguém fez e eu observei que o autor não usar eval para avaliar uma variável como um comando
O autor usou
bash -c "$1"
ao invés de
eval "$1"
Presumo que o eval seja o método preferido e, provavelmente, seja mais rápido. Isso é verdade?
Existe alguma diferença prática entre os dois? Quais são as diferenças notáveis entre os dois?
bash
shell-script
bash-script
Quem sou eu
fonte
fonte
e='echo foo'; $e
funciona muito bem.Respostas:
eval "$1"
executa o comando no script atual. Ele pode definir e usar variáveis de shell do script atual, definir variáveis de ambiente para o script atual, definir e usar funções do script atual, definir o diretório atual, umask, limites e outros atributos para o script atual e assim por diante.bash -c "$1"
executa o comando em um script completamente separado, que herda variáveis de ambiente, descritores de arquivo e outro ambiente de processo (mas não transmite nenhuma alteração de volta), mas não herda configurações internas do shell (variáveis do shell, funções, opções, traps, etc.).Existe outra maneira,
(eval "$1")
que executa o comando em um subshell: herda tudo do script de chamada, mas não transmite nenhuma alteração de volta.Por exemplo, supondo que a variável
dir
não seja exportada e$1
sejacd "$foo"; ls
:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
lista o conteúdo/somewhere/else
e as impressões/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
lista o conteúdo/somewhere/else
e as impressões/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
lista o conteúdo de/starting/directory
(porquecd ""
não altera o diretório atual) e imprime/starting/directory
.fonte
(eval "$1")
não tem nada a versource
. É apenas uma combinação de(…)
eeval
.source foo
é aproximadamente equivalente aeval "$(cat foo)"
.eval
e.dot
é queeval
trabalha com argumentos e.dot
trabalha com arquivos.A diferença mais importante entre
E
É que o primeiro roda em um subshell e o segundo não. Tão:
SAÍDA:
SAÍDA:
Não tenho idéia do porquê alguém usaria o executável
bash
dessa maneira. Se você precisar chamá-lo, use o built-in garantido POSIXsh
. Ou(subshell eval)
se você deseja proteger seu ambiente.Pessoalmente, prefiro o shell
.dot
acima de tudo.SAÍDA
MAS VOCÊ PRECISA?
A única causa a ser usada é o fato de sua variável realmente atribuir ou avaliar outra, ou a divisão de palavras é importante para a saída.
Por exemplo:
SAÍDA:
Isso funciona, mas apenas porque
echo
não se importa com a contagem de argumentos.SAÍDA:
Vejo? As aspas duplas aparecem porque o resultado da expansão de shell
$var
não é avaliadoquote-removal
.SAÍDA:
Mas com
eval
oush
:SAÍDA:
Quando usamos
eval
oush
o shell faz uma segunda passagem nos resultados das expansões e as avalia como um comando potencial também, e assim as aspas fazem a diferença. Você também pode fazer:SAÍDA
fonte
Eu fiz um teste rápido:
(Sim, eu sei, usei o bash -c para executar o loop, mas isso não deve fazer diferença).
Os resultados:
Então
eval
é mais rápido. Na página do manual deeval
:bash -c
é claro, executa o comando em um shell bash. Uma observação: usei/bin/echo
porqueecho
é um shell internobash
, o que significa que um novo processo não precisa ser iniciado. Substituindo/bin/echo
porecho
para obash -c
teste, levou1.28s
. Isso é o mesmo. No entanto,eval
é mais rápido para executar executáveis. A principal diferença aqui é queeval
não inicia um novo shell (ele executa o comando no atual) enquantobash -c
inicia um novo shell e depois executa o comando no novo shell. Iniciar um novo shell leva tempo, e é por isso quebash -c
é mais lento queeval
.fonte
bash -c
comeval
nãoexec
.bash -c
não é que ruim ...