O que você pode fazer com o eval
comando? Por que isso é útil? É algum tipo de função interna no bash? Não existe uma man
página para isso ..
help eval
para obter página "man" do seu shell
O que você pode fazer com o eval
comando? Por que isso é útil? É algum tipo de função interna no bash? Não existe uma man
página para isso ..
help eval
para obter página "man" do seu shell
Respostas:
eval
faz parte do POSIX. É uma interface que pode ser um shell embutido.
Está descrito no "Manual do Programador POSIX": http://www.unix.com/man-page/posix/1posix/eval/
eval - construct command by concatenating arguments
Vai pegar um argumento e construir um comando dele, que será executado pelo shell. Este é o exemplo da página de manual:
1) foo=10 x=foo
2) y='$'$x
3) echo $y
4) $foo
5) eval y='$'$x
6) echo $y
7) 10
$foo
com o valor '10'
e $x
com o valor 'foo'
.$y
, que consiste na string '$foo'
. O cifrão deve ser escapado com '$'
.echo $y
,.'$foo'
eval
. Ele primeiro avaliará $x
a string 'foo'
. Agora, temos a declaração y=$foo
que será avaliada y=10
.echo $y
agora é o valor '10'
.Essa é uma função comum em muitos idiomas, por exemplo, Perl e JavaScript. Veja perldoc eval para mais exemplos: http://perldoc.perl.org/functions/eval.html
eval
é um recurso interno, não uma função. Na prática, os built-ins se comportam muito como funções que não têm uma definição na linguagem, mas não tanto (como fica aparente se você tiver distorção suficiente para definir uma função chamada eval
).
Sim, eval
é um comando interno do bash, portanto, é descrito na bash
página de manual.
eval [arg ...]
The args are read and concatenated together into a single com-
mand. This command is then read and executed by the shell, and
its exit status is returned as the value of eval. If there are
no args, or only null arguments, eval returns 0.
Geralmente é usado em combinação com uma substituição de comando . Sem um explícito eval
, o shell tenta executar o resultado de uma substituição de comando, não para avaliá- lo.
Diga que deseja codificar um equivalente a VAR=value; echo $VAR
. Observe a diferença de como o shell lida com os escritos de echo VAR=value
:
andcoz@...:~> $( echo VAR=value )
bash: VAR=value: command not found
andcoz@...:~> echo $VAR
<empty line>
O shell tenta executar echo
e VAR=value
como dois comandos separados. Emite um erro sobre a segunda string. A atribuição permanece ineficaz.
andcoz@...:~> eval $( echo VAR=value )
andcoz@...:~> echo $VAR
value
O shell mescla (concatena) as duas seqüências echo
e VAR=value
analisa essa unidade única de acordo com as regras apropriadas e a executa.Por último, mas não menos importante, eval
pode ser um comando muito perigoso. Qualquer entrada em um eval
comando deve ser cuidadosamente verificada para evitar problemas de segurança.
eval
não possui uma página de manual porque não é um comando externo separado, mas um shell interno, o que significa um comando interno e conhecido apenas pelo shell ( bash
). A parte relevante da bash
página de manual diz:
eval [arg ...]
The args are read and concatenated together into a single command.
This command is then read and executed by the shell, and its exit
status is returned as the value of eval. If there are no args, or only
null arguments, eval returns 0
Além disso, a saída se help eval
é:
eval: eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
eval
é um comando poderoso e, se você pretende usá-lo, deve ter muito cuidado para evitar os possíveis riscos de segurança que o acompanham.
A instrução eval diz ao shell para pegar os argumentos de eval como comando e executá-los na linha de comando. É útil em uma situação como abaixo:
No seu script, se você estiver definindo um comando em uma variável e, posteriormente, desejar usar esse comando, use eval:
/home/user1 > a="ls | more"
/home/user1 > $a
bash: command not found: ls | more
/home/user1 > # Above command didn't work as ls tried to list file with name pipe (|) and more. But these files are not there
/home/user1 > eval $a
file.txt
mailids
remote_cmd.sh
sample.txt
tmp
/home/user1 >
ls | more
. Em outras palavras: O nome do comando único consistia em nove caracteres, incluindo os espaços e o símbolo de barra vertical .
eval é um comando shell que geralmente é implementado como um componente interno.
No POSIX, ele é listado como parte de "2.14. Utilitários embutidos especiais" na entrada "eval" .
O que significa builtin é:
O termo "interno" implica que o shell pode executar o utilitário diretamente e não precisa procurá-lo.
Em termos simples: faz com que uma linha de entrada seja analisada duas vezes .
O shell possui uma sequência de etapas a seguir para "processar" uma linha. Você pode olhar para esta imagem e perceber que eval é a única linha que sobe de volta à etapa 1, à esquerda. Na descrição do POSIX :
2.1 Introdução ao Shell
- O shell lê sua entrada ....
- O shell divide a entrada em tokens: palavras e operadores
- O shell analisa a entrada em comandos simples e compostos.
- O shell realiza várias expansões (separadamente) ...
- O shell executa o redirecionamento e remove os operadores de redirecionamento e seus operandos da lista de parâmetros.
- O shell executa uma função, arquivo executável interno ou script ...
- Opcionalmente, o shell aguarda a conclusão do comando e coleta o status de saída.
Na etapa 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 sequência de execução retorna.
É por isso que digo: Com eval, uma linha de entrada é analisada duas vezes .
E efeito mais importante para entender. É que uma consequência da primeira vez que uma linha está sujeita às sete passos shell mostrados acima, está citando . Na etapa 4 (expansões), também há uma sequência de etapas para executar todas as expansões , a última das quais é Remoção de cotação :
A remoção da cotação deve sempre ser realizada por último.
Portanto, sempre, há um nível de cotação removido.
Como conseqüência desse primeiro efeito, partes adicionais / diferentes da linha ficam expostas à análise de shell e a todas as outras etapas.
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 citação é removido, tornando o primeiro $
não citado.
Fim do primeiro loop.
É então, no segundo loop, que a string $b
é lida pelo shell.
Então expandido para "c"
E dado como argumento para echo
.
Para "ver" o que o eval produzirá no primeiro loop (para ser avaliado novamente), use echo. Ou qualquer comando / script / programa que mostre claramente os argumentos:
$ a=b b=c
$ eval echo \$$a;
c
Substitua eval por eco 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>
Que, neste exemplo, é apenas um eco e uma variável, mas lembre-se de ajudar na avaliação de casos mais complexos.
Deve-se dizer que: há um erro no código acima, você vê?
Fácil: faltam algumas aspas.
Quão? 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 ocorre porque o valor interno $b
foi dividido pelo shell.
Se isso não o convencer, 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.
Citações ausentes. Para fazê-lo funcionar corretamente (adicione aspas internas "$a"
e externas \"
).
Tente isto (é perfeitamente seguro):
$ a=b b="hi * jk"
$ eval echo \" \$"$a" \"
hi * jk
Não existe uma página de manual para isso ..
Não, não há uma página de manual independente para isso. A pesquisa de manual com man -f eval
ou mesmo apropos eval
não mostra entrada.
Está incluído no interior man bash
. Como é qualquer embutido.
Procure por "SHELL BUILTIN COMMANDS" e depois por "eval".
Uma maneira mais fácil de obter ajuda é: No bash, você pode fazer help eval
para ver a ajuda do built-in.
Porque está vinculando o texto ao código dinamicamente.
Em outras palavras: converte a lista de seus argumentos (e / ou expansões de tais argumentos) em uma linha executada. Se, por qualquer 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 a quem definiu o valor de um ou vários argumentos:
Vamos, sente-se aqui e digite qualquer linha de comando, eu irei executá-lo com meus poderes.
Isso é perigoso? Deve ser claro para todos que é.
A regra de segurança para eval deve ser:
Execute eval apenas nas variáveis às quais você deu valor.
Leia mais detalhes aqui .
eval
é uma característica das línguas mais interpretadas ( TCL
, python
, ruby
...), não apenas conchas. É usado para avaliar o código dinamicamente.
Em shells, é implementado como um comando embutido no shell.
Basicamente, eval
pega uma string como argumento e avalia / interpreta o código nela. Em shells, eval
pode levar mais de um argumento, mas eval
apenas concatena aqueles para formar a string a ser avaliada.
É muito poderoso porque você pode construir código dinamicamente e executá-lo, algo que não pode ser feito em linguagens compiladas como C.
Gostar:
varname=$1 varvalue=$2
eval "$varname=\$varvalue" # evaluate a string like "foo=$varvalue"
# which in Bourne-like shell language
# is a variable assignment.
Mas também é perigoso, pois é importante higienizar as partes dinâmicas (fornecidas externamente) do que é passado eval
pelo mesmo motivo que é interpretado como código do shell.
Por exemplo, acima de se $1
for evil-command; var
, eval
acabaria avaliando o evil-command; var=$varvalue
código do shell e o executaria evil-command
.
A maldade de eval
muitas vezes é exagerada.
OK, é perigoso, mas pelo menos sabemos que é perigoso.
Um monte de outros comandos irá avaliar o código shell em seus argumentos, se não higienizado, como (dependendo do shell), [
aka test
, export
, printf
, GNU sed
, awk
e, claro, sh
/ bash
/ perl
e todos os intérpretes ...
Exemplos (aqui usando uname
como os evil-command
e $a
como dados não autorizados fornecidos externamente):
$ a='$(uname>&2)' sh -c 'eval "echo $a"'
Linux
$ a='x[0$(uname>&2)]' mksh -c 'export "$a=$b"'
Linux
$ a='x[0$(uname>&2)]' ksh93 -c 'printf "%d\n" "$a"'
Linux
0
$ a='x[0$(uname>&2)]' ksh93 -c '[ "$a" -gt 0 ]'
Linux
$ a=$'bar/g;e uname>&2\n;s//'; echo foo | sed "s/foo/$a/g"
Linux
bar
$ a='";system("uname");"'; awk "BEGIN{print \"$a\"}"
Linux
$ a=';uname'; sh -c "echo $a"
Linux
Aqueles sed
, export
... comandos poderia ser considerado mais perigoso porque enquanto é óbvio eval "$var"
fará com que o conteúdo $var
a ser avaliado como código shell, não é tão óbvio com sed "s/foo/$var/"
ou export "$var=value"
ou [ "$var" -gt 0 ]
. A perigosidade é a mesma, mas está oculta nesses outros comandos.
sed
como eval
está sendo passado uma string contida em uma variável, e para ambos, o conteúdo dessa string acaba sendo avaliado como código shell, então sed
é tão perigoso quanto eval
, é o que estou dizendo. sed
está passando uma string contendo uname
(uname ainda não foi executado) e, através da invocação de sed
, o comando uname acaba sendo executado. Como para avaliação. Em sed 's/foo/$a/g'
, você não está transmitindo dados não autorizados sed
, não é disso que estamos falando aqui.
Este exemplo pode lançar alguma luz:
#!/bin/bash
VAR1=25
VAR2='$VAR1'
VAR3='$VAR2'
echo "$VAR3"
eval echo "$VAR3"
eval eval echo "$VAR3"
Saída do script acima:
$VAR2
$VAR1
25
eval
. Você acredita que há algum aspecto fundamental e fundamental da funcionalidade eval
que não é abordado nas respostas existentes? Nesse caso, explique -o e use o exemplo para ilustrar sua explicação. Por favor, não responda nos comentários; edite sua resposta para torná-la mais clara e completa.
type command
para saber de que tipo é um comando . (type eval
neste caso)