Atualização: algumas pessoas dizem que nunca se deve usar avaliação. Discordo. Eu acho que o risco surge quando uma entrada corrompida pode ser passada para eval. No entanto, existem muitas situações comuns em que isso não representa um risco e, portanto, vale a pena saber como usar o eval em qualquer caso. Essa resposta do stackoverflow explica os riscos da avaliação e as alternativas à avaliação. Por fim, cabe ao usuário determinar se / quando a avaliação é segura e eficiente de usar.
A evalinstrução bash permite executar linhas de código calculadas ou adquiridas pelo seu script bash.
Talvez o exemplo mais direto seja um programa bash que abra outro script bash como um arquivo de texto, leia cada linha de texto e use evalpara executá-los em ordem. Esse é essencialmente o mesmo comportamento da sourceinstrução bash , que é o que se usaria, a menos que fosse necessário realizar algum tipo de transformação (por exemplo, filtragem ou substituição) no conteúdo do script importado.
Raramente precisei eval, mas achei útil ler ou escrever variáveis cujos nomes estavam contidos em cadeias atribuídas a outras variáveis. Por exemplo, para executar ações em conjuntos de variáveis, mantendo o tamanho do código pequeno e evitando redundância.
evalé conceitualmente simples. No entanto, a sintaxe estrita do idioma bash e a ordem de análise do intérprete do bash podem ser diferenciadas e evalparecer enigmáticas e difíceis de usar ou entender. Aqui estão os itens essenciais:
O argumento passado para evalé uma expressão de cadeia que é calculada em tempo de execução. evalexecutará o resultado final analisado de seu argumento como uma linha de código real em seu script.
A sintaxe e a ordem de análise são rigorosas. Se o resultado não for uma linha executável de código bash, no escopo do seu script, o programa falhará na evalinstrução ao tentar executar o lixo.
Ao testar, você pode substituir a evalinstrução echoe ver o que é exibido. Se for um código legítimo no contexto atual, sua execução evalfuncionará.
Os exemplos a seguir podem ajudar a esclarecer como o eval funciona ...
Exemplo 1:
eval A declaração na frente do código 'normal' é um NOP
$ eval a=b
$ eval echo $a
b
No exemplo acima, as primeiras evalinstruções não têm finalidade e podem ser eliminadas. evalé inútil na primeira linha porque não há aspecto dinâmico no código, ou seja, ele já foi analisado nas linhas finais do código bash, portanto, seria idêntico como uma declaração normal de código no script bash. O segundo também evalé inútil, porque, embora exista uma etapa de análise convertida $apara o seu equivalente literal de cadeia de caracteres, não há indireção (por exemplo, nenhuma referência via valor da cadeia de um substantivo bash real ou variável de script realizada por bash), portanto se comportaria de forma idêntica como uma linha de código sem o evalprefixo.
Exemplo 2:
Execute a atribuição de var usando nomes de var passados como valores de sequência.
$ key="mykey"
$ val="myval"
$ eval $key=$val
$ echo $mykey
myval
Se você fosse echo $key=$val, a saída seria:
mykey=myval
Que , sendo o resultado final da análise de cadeia, é o que será executado por eval, portanto, o resultado da instrução echo no final ...
Exemplo 3:
Incluindo mais Indireção no Exemplo 2
$ keyA="keyB"
$ valA="valB"
$ keyB="that"
$ valB="amazing"
$ eval eval \$$keyA=\$$valA
$ echo $that
amazing
O exposto acima é um pouco mais complicado que o exemplo anterior, confiando mais na ordem de análise e nas peculiaridades do bash. A evallinha seria aproximadamente analisada internamente na seguinte ordem (observe que as seguintes instruções são pseudocódigo, não código real, apenas para tentar mostrar como a instrução seria dividida em etapas internamente para chegar ao resultado final) .
eval eval \$$keyA=\$$valA # substitution of $keyA and $valA by interpreter
eval eval \$keyB=\$valB # convert '$' + name-strings to real vars by eval
eval $keyB=$valB # substitution of $keyB and $valB by interpreter
eval that=amazing # execute string literal 'that=amazing' by eval
Se a ordem de análise assumida não explica o que a avaliação está fazendo o suficiente, o terceiro exemplo pode descrever a análise com mais detalhes para ajudar a esclarecer o que está acontecendo.
Exemplo 4:
Descubra se os vars, cujos nomes estão contidos em cadeias, eles próprios contêm valores de cadeia.
a="User-provided"
b="Another user-provided optional value"
c=""
myvarname_a="a"
myvarname_b="b"
myvarname_c="c"
for varname in "myvarname_a" "myvarname_b" "myvarname_c"; do
eval varval=\$$varname
if [ -z "$varval" ]; then
read -p "$varname? " $varname
fi
done
Na primeira iteração:
varname="myvarname_a"
Bash analisa o argumento evale evalvê literalmente isso em tempo de execução:
eval varval=\$$myvarname_a
O pseudocódigo a seguir tenta ilustrar como o bash interpreta a linha de código real acima , para chegar ao valor final executado por eval. (as seguintes linhas descritivas, não o código bash exato):
1. eval varval="\$" + "$varname" # This substitution resolved in eval statement
2. .................. "$myvarname_a" # $myvarname_a previously resolved by for-loop
3. .................. "a" # ... to this value
4. eval "varval=$a" # This requires one more parsing step
5. eval varval="User-provided" # Final result of parsing (eval executes this)
Depois que toda a análise é feita, o resultado é o que é executado, e seu efeito é óbvio, demonstrando que não há nada particularmente misterioso sobre evalsi mesmo, e a complexidade está na análise de seu argumento.
varval="User-provided"
O código restante no exemplo acima simplesmente testa para verificar se o valor atribuído a $ varval é nulo e, nesse caso, solicita que o usuário forneça um valor.
$($n)é executado$nem um subshell. Ele tenta executar o comando1que não existe.