Comment utiliser eval dans les scripts Linux Bash

fatmawati achmad zaenuri/Shutterstock.com

De toutes les commandes Bash, pauvre vieux eval a probablement la pire réputation. Justifié, ou juste mauvaise presse ? Nous discutons de l’utilisation et des dangers de cette commande Linux la moins appréciée.

Nous devons parler d’eval

Utilisé avec insouciance, eval peut conduire à un comportement imprévisible et même à des insécurités du système. D’après les sons, nous ne devrions probablement pas l’utiliser, n’est-ce pas ? Eh bien pas tout à fait.

Vous pourriez dire quelque chose de similaire à propos des automobiles. Entre de mauvaises mains, ils sont une arme mortelle. Les gens les utilisent dans des raids de bélier et comme véhicules de fuite. Devrions-nous tous arrêter d’utiliser des voitures ? Non bien sûr que non. Mais ils doivent être utilisés correctement et par des personnes qui savent les conduire.

L’adjectif usuel appliqué à eval est « mal ». Mais tout dépend de la façon dont il est utilisé. La eval commande rassemble les valeurs à partir d’une ou plusieurs variables. Il crée une chaîne de commande. Il exécute ensuite cette commande. Cela le rend utile lorsque vous devez faire face à des situations où le contenu d’une commande est dérivé dynamiquement lors de l’exécution de votre script.

Des problèmes surviennent lorsqu’un script est écrit pour être utilisé eval sur une chaîne qui a été reçue de quelque part à l’extérieur le scénario. Il peut être saisi par un utilisateur, envoyé via une API, étiqueté sur une requête HTTPS ou n’importe où ailleurs en dehors du script.

Si la chaîne qui eval va travailler n’a pas été dérivée localement et par programmation, il existe un risque que la chaîne contienne des instructions malveillantes intégrées ou d’autres entrées mal formées. De toute évidence, vous ne voulez pas eval pour exécuter des commandes malveillantes. Donc, pour être sûr, n’utilisez pas eval avec des chaînes générées en externe ou une entrée utilisateur.

Premiers pas avec eval

La eval La commande est une commande intégrée du shell Bash. Si Bash est présent, eval sera présent.

eval concatène ses paramètres en une seule chaîne. Il utilisera un seul espace pour séparer les éléments concaténés. Il évalue les arguments, puis passe la chaîne entière au shell pour qu’il s’exécute.

Créons une variable appelée wordcount.

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

La variable de chaîne contient une commande pour compter les mots dans un fichier appelé « raw-notes.md ».

On peut utiliser eval pour exécuter cette commande en lui passant le évaluer de la variable.

Utiliser eval avec une variable de chaîne pour compter les mots dans un fichier

La commande est exécutée dans le shell courant, pas dans un sous-shell. Nous pouvons facilement le montrer. Nous avons un court fichier texte appelé « variables.txt ». Il contient ces deux lignes.

first=How-To
second=Geek

Nous utiliserons cat pour envoyer ces lignes à la fenêtre du terminal. Ensuite, nous utiliserons eval évaluer un cat commande afin que les instructions à l’intérieur du fichier texte soient exécutées. Cela définira les variables pour nous.

cat variables.txt
eval "$(cat variables.txt)"
echo $first $second

Accéder aux variables définies par eval dans le shell actuel

En utilisant echo pour imprimer les valeurs des variables, nous pouvons voir que eval La commande s’exécute dans le shell actuel, pas dans un sous-shell.

Un processus dans un sous-shell ne peut pas modifier l’environnement shell du parent. Étant donné que eval s’exécute dans le shell actuel, les variables définies par eval sont utilisables depuis le shell qui a lancé le eval commande.

Notez que si vous utilisez eval dans un script, le shell qui serait modifié par eval est le sous-shell dans lequel le script s’exécute, pas le shell qui l’a lancé.

EN RELATION: Comment utiliser les commandes Linux cat et tac

Utilisation de variables dans la chaîne de commande

Nous pouvons inclure d’autres variables dans les chaînes de commande. Nous allons définir deux variables pour contenir des entiers.

num1=10 
num2=7

Nous allons créer une variable pour contenir un expr commande qui renverra la somme de deux nombres. Cela signifie que nous devons accéder aux valeurs des deux variables entières dans la commande. Notez les backticks autour du expr déclaration.

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

Nous allons créer une autre commande pour nous montrer le résultat de la expr déclaration.

show="echo"

Notez qu’il n’est pas nécessaire d’inclure un espace à la fin du echo chaîne, ni au début de la expr chaîne de caractères. eval s’en occupe.

Et pour exécuter toute la commande, nous utilisons :

eval $show $add

Utilisation de variables dans la chaîne de commande

Les valeurs des variables à l’intérieur du expr chaîne sont remplacés dans la chaîne par eval avant qu’il ne soit passé au shell pour être exécuté.

EN RELATION: Comment travailler avec des variables dans Bash

Accéder aux variables à l’intérieur des variables

Vous pouvez affecter une valeur à une variable, puis affecter le Nom de cette variable à une autre variable. Utilisant evalvous pouvez accéder au évaluer contenue dans la première variable, à partir de son nom qui est le évaluer stocké dans la deuxième variable. Un exemple vous aidera à démêler cela.

Copiez ce script dans un éditeur et enregistrez-le dans un fichier appelé « assign.sh ».

#!/bin/bash

title="How-To Geek"
webpage=title
command="echo"
eval $command $$webpage

Nous devons le rendre exécutable avec le chmod commande.

chmod +x assign.sh

Utiliser chmod pour rendre un script exécutable

Vous devrez le faire pour tous les scripts que vous copiez à partir de cet article. Utilisez simplement le nom de script approprié dans chaque cas.

Lorsque nous exécutons notre script, nous voyons le texte de la variable title Même si le eval la commande utilise la variable webpage.

./assign.sh

Accéder à la valeur d'une variable à partir de son nom stocké dans une autre variable

Le signe dollar échappé « $« et les bretelles »” oblige eval à examiner la valeur contenue dans la variable dont le nom est stocké dans le webpage variable.

Utilisation de variables créées dynamiquement

On peut utiliser eval pour créer dynamiquement des variables. Ce script s’appelle « loop.sh ».

#!/bin/bash

total=0
label="Looping complete. Total:"

for n in 1..10
do
  eval x$n=$n
  echo "Loop" $x$n
  ((total+=$x$n))
done

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

echo $label $total

Il crée une variable appelée total qui contient la somme des valeurs des variables que nous créons. Il crée ensuite une variable de chaîne appelée label. Il s’agit d’une simple chaîne de texte.

Nous allons boucler 10 fois et créer 10 variables appelées x1 jusqu’à x10. La eval l’instruction dans le corps de la boucle fournit le « x » et prend la valeur du compteur de boucle $n pour créer le nom de la variable. En même temps, il met la nouvelle variable à la valeur du compteur de boucle $n.

Il imprime la nouvelle variable dans la fenêtre du terminal, puis incrémente le total variable avec la valeur de la nouvelle variable.

En dehors de la boucle, les 10 nouvelles variables sont imprimées une fois de plus, toutes sur une seule ligne. Notez que nous pouvons également faire référence aux variables par leurs noms réels, sans utiliser de version calculée ou dérivée de leurs noms.

Enfin, nous imprimons la valeur de total variable.

./loop.sh

Utiliser eval pour créer dynamiquement des variables

EN RELATION: Abécédaire : Boucles Bash : pour, pendant et jusqu’à

Utiliser eval avec des tableaux

Imaginez un scénario dans lequel vous avez un script qui dure longtemps et qui effectue un certain traitement pour vous. Il écrit dans un fichier journal avec un nom créé à partir d’un horodatage. Parfois, il démarre un nouveau fichier journal. Lorsque le script est terminé, s’il n’y a pas eu d’erreurs, il supprime les fichiers journaux qu’il a créés.

Vous ne voulez pas simplement rm *.log, vous souhaitez qu’il supprime uniquement les fichiers journaux qu’il a créés. Ce script simule cette fonctionnalité. Il s’agit de « clear-logs.sh ».

#!/bin/bash

declare -a logfiles

filecount=0 
rm_string="echo"

function create_logfile() 
  ((++filecount))
  filename=$(date +"%Y-%m-%d_%H-%M-%S").log
  logfiles[$filecount]=$filename
  echo $filecount "Created" $logfiles[$filecount]


# body of the script. Some processing is done here that
# periodically generates a log file. We'll simulate that
create_logfile
sleep 3
create_logfile
sleep 3
create_logfile
sleep 3
create_logfile

# are there any files to remove?
for ((file=1; file<=$filecount; file++))
do
  # remove the logfile
  eval $rm_string $logfiles[$file] "deleted..."
  logfiles[$file]=""
done

Le script déclare un tableau appelé logfiles . Cela contiendra les noms des fichiers journaux créés par le script. Il déclare une variable appelée filecount . Cela contiendra le nombre de fichiers journaux qui ont été créés.

Il déclare également une chaîne appelée rm_string. Dans un script du monde réel, cela contiendrait le rm commande, mais nous utilisons echo afin que nous puissions démontrer le principe de manière non destructive.

La fonction create_logfile() est l’endroit où chaque fichier journal est nommé et où il sera ouvert. Nous ne faisons que créer le nom de fichieret prétendant qu’il a été créé dans le système de fichiers.

La fonction incrémente le filecount variable. Sa valeur initiale est zéro, donc le premier nom de fichier que nous créons est stocké en position un dans le tableau. Ceci est fait exprès, ainsi voir plus tard.

Le nom de fichier est créé à l’aide de la date commande et l’extension « .log ». Le nom est stocké dans le tableau à la position indiquée par filecount. Le nom est imprimé dans la fenêtre du terminal. Dans un script réel, vous créeriez également le fichier réel.

Le corps du script est simulé à l’aide de la sleep commande. Il crée le premier fichier journal, attend trois secondes, puis en crée un autre. Il crée quatre fichiers journaux, espacés de manière à ce que les horodatages de leurs noms de fichiers soient différents.

Enfin, il y a une boucle qui supprime les fichiers journaux. Le fichier de compteur de boucles est défini sur un. Il compte jusqu’à et y compris la valeur de filecountqui contient le nombre de fichiers qui ont été créés.

Si filecount est toujours défini sur zéro, car aucun fichier journal n’a été créé, le corps de la boucle ne sera jamais exécuté car un n’est pas inférieur ou égal à zéro. C’est pourquoi le filecount la variable était définie sur zéro lorsqu’elle a été déclarée et pourquoi elle a été incrémentée avant de le premier fichier a été créé.

A l’intérieur de la boucle, on utilise eval avec notre non destructif rm_string et le nom du fichier qui est extrait du tableau. Nous définissons ensuite l’élément de tableau sur une chaîne vide.

C’est ce que nous voyons lorsque nous exécutons le script.

./clear-logs.sh

Suppression de fichiers dont les noms sont stockés dans un tableau

Tout n’est pas mauvais

Très décrié eval a certainement ses utilisations. Comme la plupart des outils, utilisé imprudemment, il est dangereux, et à plus d’un titre.

Si vous vous assurez que les chaînes sur lesquelles il fonctionne sont créées en interne et non capturées par des humains, des API ou des choses comme les requêtes HTTPS, vous éviterez les principaux pièges.

EN RELATION: Comment afficher la date et l’heure dans le terminal Linux (et l’utiliser dans les scripts bash)

Source-135