O que é eval?
eval é um comando shell que geralmente é implementado como um arquivo interno.
No POSIX ele é listado como parte de "2.14. Utilitários Internos Especiais" na entrada "eval" .
O que significa embutir é:
The term "built-in" implies that the shell can execute the utility directly and does not need to search for it.
O que isso faz?
Em termos simples: faz com que uma linha de entrada seja analisada duas vezes .
Como isso acontece?
O shell tem uma sequência de etapas que segue para "processar" uma linha.
Você poderia olhar para esta imagem e perceber que eval é a única linha que sobe, de volta ao passo 1, à esquerda.
De a descrição POSIX :
2.1 Shell Introduction
- The shell reads its input ....
- The shell breaks the input into tokens: words and operators
- The shell parses the input into simple and compound commands.
- The shell performs various expansions (separately) ...
- The shell performs redirection and removes redirection operators and their operands from the parameter list.
- The shell executes a function, built-in, executable file, or script ...
- The shell optionally waits for the command to complete and collects the exit status.
No passo 6, um built-in será executado.
Na etapa 6 eval faz com que a linha processada seja enviada de volta para a etapa 1.
É a única condição sob a qual a seqüência de execução retorna.
That is why I say: With eval an input line is parsed twice.
Efeitos da análise duas vezes.
O primeiro.
E efeito mais importante para entender. Essa é uma consequência da primeira vez que uma linha está sujeita às sete etapas de shell mostradas acima, é citando . Na etapa 4 (expansões), há também uma sequência de etapas para realizar todas as expansões , o último dos quais é Quote Removal :
Quote removal shall always be performed last.
Então, sempre, há um nível de cotação removido.
Segundo.
Como consequência desse primeiro efeito, partes adicionais / diferentes da linha ficam expostas à análise de shell e a todas as outras etapas.
Exemplo.
Indirection.
Isso permite executar expansões indiretas:
a=b b=c ; eval echo \$$a ### shall produce "c"
Por quê?
Porque no primeiro loop, o primeiro $
é citado.
Como tal, é ignorado para expansões pelo shell.
O próximo $
com o nome a é expandido para produzir "b".
Em seguida, um nível de cotação é removido, fazendo com que o primeiro $
não seja cotado.
Fim do primeiro loop.
É então, no segundo loop, que a string $b
é lida pelo shell.
Em seguida, expandido para "c"
E dado como um argumento para echo
.
Para "ver" o que o eval produzirá no primeiro loop (para ser avaliado novamente), use o echo. Ou qualquer comando / script / programa que mostre claramente os argumentos:
$ a=b b=c
$ eval echo \$$a;
c
Substitua eval por echo para "ver" o que está acontecendo:
$ echo echo \$$a
echo $b
Também é possível mostrar todas as "partes" de uma linha com:
$ printf '<%s> ' echo \$$a
<echo> <$b>
O qual, neste exemplo, é apenas um eco e uma variável, mas lembre-se disso para ajudar na avaliação de casos mais complexos.
Uma correção.
Deve-se dizer que: há um erro no código acima, você pode vê-lo?
Fácil: há algumas citações faltando.
Como? você pode perguntar. Simples, vamos mudar as variáveis (não o código):
$ a=b b="hi jk"
$ eval echo \$$a
hi jk
Veja os espaços que faltam?
Isso porque o valor dentro de $b
foi dividido pelo shell.
Se isso não convencer você, tente o seguinte:
$ a=b b="hi * jk"
$ eval echo \$$a ### warning this will expand to the list
### of all files in the present directory.
Por quê?
Citações ausentes. Para que funcione corretamente (adicione "$a"
interno e externo \"
quotes).
Tente isso (é perfeitamente seguro):
$ a=b b="hi * jk"
$ eval echo \" \$"$a" \"
hi * jk
Sobre o manual:
There is no man page for it..
Não, não há uma página de manual independente para isso.
A pesquisa por manual com man -f eval
ou mesmo apropos eval
não mostra entrada.
Está incluído dentro de man bash
. Como é qualquer built-in.
Procure por "SHELL BUILTIN COMMANDS" e depois por "eval".
Uma maneira mais fácil de obter ajuda é:
No bash, você poderia fazer help eval
para ver a ajuda do built-in.
Por que o eval é chamado de mal?
Porque está vinculando texto ao código dinamicamente.
Em outras palavras: ele converte a lista de seus argumentos (e / ou expansões de tais argumentos) em uma linha executada. Se por algum motivo, um argumento tiver sido definido por um invasor, você estará executando o código do invasor.
Ou ainda mais simples, com eval você está dizendo quem definiu o valor de um ou vários argumentos:
C'mon, sit here and type any command line, I will execute it with my powers.
Isso é perigoso? Deve ficar claro para todos que é.
A regra de segurança para eval deve ser:
Apenas execute eval em variáveis para as quais você atribuiu seu valor.
Leia mais detalhes aqui .