Como usar eval em scripts Bash do Linux

Laptop Linux mostrando um prompt do bash

De todos os comandos Bash, o pobre e velho evalprovavelmente tem a pior reputação. Justificado ou apenas má publicidade? Discutimos o uso e os perigos desse comando menos apreciado do Linux.

Precisamos conversar sobre avaliação

Usado de forma descuidada, evalpode levar a comportamentos imprevisíveis e até mesmo a inseguranças do sistema. Pelo que parece, provavelmente não deveríamos usá-lo, certo? Bem, não exatamente.

Você poderia dizer algo semelhante sobre automóveis. Nas mãos erradas, são uma arma mortal. As pessoas os usam em ataques de aríetes e como veículos de fuga. Deveríamos todos parar de usar carros? Não, claro que não. Mas têm de ser utilizados de forma adequada e por pessoas que saibam conduzi-los.

O adjetivo usualmente aplicado evalé “mal”. Mas tudo se resume a como está sendo usado. O

 eval  

O comando agrupa os valores de uma ou mais variáveis . Ele cria uma string de comando. Em seguida, ele executa esse comando. Isso o torna útil quando você precisa lidar com situações em que o conteúdo de um comando é derivado dinamicamente durante a execução do seu script .

Os problemas surgem quando um script é escrito para ser usado evalem uma string recebida de algum lugar fora do script. Pode ser digitado por um usuário, enviado por meio de uma API, marcado em uma solicitação HTTPS ou em qualquer outro lugar externo ao script.

Se a cadeia de caracteres na qual evalirá funcionar não foi derivada localmente e programaticamente, existe o risco de a cadeia de caracteres conter instruções maliciosas incorporadas ou outras entradas mal formadas. Obviamente, você não deseja evalexecutar comandos maliciosos. Portanto, para garantir, não use evalstrings geradas externamente ou entradas do usuário.

Primeiros passos com avaliação

O evalcomando é um comando interno do shell Bash. Se Bash estiver presente, evalestará presente.

evalconcatena seus parâmetros em uma única string. Ele usará um único espaço para separar os elementos concatenados. Ele avalia os argumentos e então passa a string inteira para o shell executar.

Vamos criar uma variável chamada

 wordcount 

.

wordcount="wc -w raw-notes.md"

A variável string contém um comando para contar as palavras em um arquivo chamado “raw-notes.md”.

Podemos usar evalpara executar esse comando passando-lhe o valor da variável.

 eval "$wordcount" 
Usando eval com uma variável string para contar as palavras em um arquivo

O comando é executado no shell atual, não em um subshell. Podemos facilmente mostrar isso. Temos um pequeno arquivo de texto chamado “variables.txt”. Ele contém essas duas linhas.

Recomendado:  Como atualizar seu Apple Watch

primeiro = Como fazer

segundo = Geek

Usaremos catpara enviar essas linhas para a janela do terminal. Em seguida, usaremos evalpara avaliar um catcomando para que as instruções dentro do arquivo de texto sejam executadas. Isso definirá as variáveis ​​para nós.

variáveis ​​​​de gato.txt

avaliação "$(cat variáveis.txt)"

echo $ primeiro $ segundo

Acessando variáveis ​​definidas por eval no shell atual

Ao echoimprimir os valores das variáveis, podemos ver que evalo comando é executado no shell atual, não em um subshell.

Um processo em um subshell não pode alterar o ambiente shell do pai. Como eval é executado no shell atual, as variáveis ​​definidas por evalpodem ser utilizadas no shell que iniciou o evalcomando.

Observe que se você usar evalem um script, o shell que será alterado evalserá o subshell em que o script está sendo executado, não o shell que o iniciou.

Usando variáveis ​​na string de comando

Podemos incluir outras variáveis ​​nas strings de comando. Definiremos duas variáveis ​​para armazenar números inteiros.

num1=10

num2=7

Criaremos uma variável para armazenar um exprcomando que retornará a soma de dois números. Isso significa que precisamos acessar os valores das duas variáveis ​​inteiras no comando. Observe os crases em torno da exprdeclaração.

add="`expr $num1 + $num2`"

Criaremos outro comando para nos mostrar o resultado da exprinstrução.

mostrar = "eco"

Observe que não precisamos incluir um espaço no final da echostring, nem no início da exprstring. evalcuida disso.

E para executar todo o comando usamos:

avaliar $ mostrar $ adicionar

Usando variáveis ​​na string de comando

Os valores das variáveis ​​dentro da exprstring são substituídos na string por eval, antes de serem passados ​​para o shell para serem executados.

Acessando Variáveis ​​Dentro de Variáveis

Você pode atribuir um valor a uma variável e, em seguida, atribuir o nome dessa variável a outra variável. Usando eval, você pode acessar o valor contido na primeira variável, a partir do seu nome que é o valor armazenado na segunda variável. Um exemplo irá ajudá-lo a desvendar isso.

Copie este script para um editor e salve-o como um arquivo chamado “assign.sh”.

#!/bin/bash

title="Como fazer Geek"

página da web=título

comando = "eco"

avaliação $comando \${$página da web}

Precisamos torná-lo executável com o chmodcomando .

chmod +x atribuir.sh

Usando chmod para tornar um script executável

Você precisará fazer isso para todos os scripts copiados deste artigo. Basta usar o nome de script apropriado em cada caso.

Recomendado:  Quanto valem seus dados para os anunciantes?

Quando executamos nosso script, vemos o texto da variável, titlemesmo que o evalcomando esteja usando a variável webpage.

./atribuir.sh

Acessando o valor de uma variável a partir de seu nome armazenado em outra variável

O cifrão escapado ” $” e as chaves ” {}” fazem com que eval observe o valor contido dentro da variável cujo nome está armazenado na webpagevariável.

Usando variáveis ​​criadas dinamicamente

Podemos usar evalpara criar variáveis ​​dinamicamente. Este script é chamado de “loop.sh”.

#!/bin/bash

total=0

label="Loop concluído. Total:"

para n em {1..10}

fazer

avaliação x$n=$n

echo "Loop" $x$n

((total+=$x$n))

feito

ecoar $x1 $x2 $x3 $x4 $x5 $x6 $x7 $x8 $x9 $x10

eco $ rótulo $ total

Ele cria uma variável chamada totalque contém a soma dos valores das variáveis ​​que criamos. Em seguida, ele cria uma variável de string chamada label. Esta é uma sequência simples de texto.

Faremos um loop 10 vezes e criaremos 10 variáveis ​​chamadas x1até x10. A evalinstrução no corpo do loop fornece o “x” e utiliza o valor do contador do loop $npara criar o nome da variável. Ao mesmo tempo, ele define a nova variável para o valor do contador de loop $n.

Ele imprime a nova variável na janela do terminal e então incrementa a totalvariável com o valor da nova variável.

Fora do loop, as 10 novas variáveis ​​são impressas mais uma vez, todas em uma linha. Observe que também podemos nos referir às variáveis ​​pelos seus nomes reais, sem usar uma versão calculada ou derivada de seus nomes.

Finalmente, imprimimos o valor da totalvariável.

./loop.sh

Usando eval para criar variáveis ​​dinamicamente

Usando eval com matrizes

Imagine um cenário em que você tem um script de longa execução e realizando algum processamento para você. Ele grava em um arquivo de log com um nome criado a partir de um carimbo de data/hora . Ocasionalmente, ele iniciará um novo arquivo de log. Quando o script for concluído, se não houver erros, ele excluirá os arquivos de log criados.

Você não quer que isso aconteça simplesmente rm *.log, você só quer que ele exclua os arquivos de log que ele criou. Este script simula essa funcionalidade. Este é “clear-logs.sh”.

#!/bin/bash

declare -a arquivos de log

contagem de arquivos=0

rm_string="eco"

função criar_logfile() {

((++contagem de arquivos))

nome do arquivo=$(data +"%Y-%m-%d_%H-%M-%S").log

arquivos de log[$filecount]=$nome do arquivo

echo $filecount "Criado" ${logfiles[$filecount]}

}

#corpo do script. Algum processamento é feito aqui que

# gera periodicamente um arquivo de log. Vamos simular isso

criar_arquivo de log

dormir 3

criar_arquivo de log

dormir 3

criar_arquivo de log

dormir 3

criar_arquivo de log

# há algum arquivo para remover?

for ((arquivo=1; arquivo<=$contagem de arquivos; arquivo++))

fazer

#remove o arquivo de log

eval $rm_string ${logfiles[$file]} "excluído..."

arquivos de log[$arquivo]=""

feito

O script declara um array chamado logfiles. Isso conterá os nomes dos arquivos de log criados pelo script. Ele declara uma variável chamada filecount. Isso conterá o número de arquivos de log que foram criados.

Recomendado:  Como a latência pode fazer com que conexões rápidas com a Internet pareçam lentas

Ele também declara uma string chamada rm_string. Em um script do mundo real, isso conteria o rm comando , mas estamos usandoecho para demonstrar o princípio de maneira não destrutiva.

A função create_logfile()é onde cada arquivo de log é nomeado e onde seria aberto. Estamos apenas criando o nome do arquivo e fingindo que ele foi criado no sistema de arquivos.

A função incrementa a filecountvariável. Seu valor inicial é zero, então o primeiro nome de arquivo que criamos é armazenado na posição um do array. Isso é feito de propósito, como veremos mais tarde.

O nome do arquivo é criado usando o datecomando e a extensão “.log”. O nome é armazenado na matriz na posição indicada por filecount. O nome é impresso na janela do terminal. Em um script do mundo real, você também criaria o arquivo real.

O corpo do script é simulado usando o sleepcomando . Ele cria o primeiro arquivo de log, aguarda três segundos e cria outro. Ele cria quatro arquivos de log, espaçados para que os carimbos de data e hora em seus nomes de arquivos sejam diferentes.

Finalmente, há um loop que exclui os arquivos de log. O arquivo do contador de loop está definido como um. Ele conta até e incluindo o valor de filecount, que contém o número de arquivos que foram criados.

Se filecountainda estiver definido como zero — porque nenhum arquivo de log foi criado — o corpo do loop nunca será executado porque um não é menor ou igual a zero. É por isso que a filecountvariável foi definida como zero quando foi declarada e foi incrementada antes da criação do primeiro arquivo.

Dentro do loop, usamos evalo nosso não destrutivo rm_stringe o nome do arquivo que é recuperado do array. Em seguida, definimos o elemento do array como uma string vazia.

Isso é o que vemos quando executamos o script.

./clear-logs.sh

Excluindo arquivos cujos nomes estão armazenados em uma matriz

Nem tudo é ruim

Muito difamado eval definitivamente tem sua utilidade. Como a maioria das ferramentas, usada de forma imprudente, é perigosa e em mais de um aspecto.

Se você garantir que as strings nas quais ele funciona sejam criadas internamente e não capturadas de humanos, APIs ou coisas como solicitações HTTPS, você evitará as principais armadilhas.