Come utilizzare eval negli script Bash di Linux

Pubblicato: 2022-08-22
Laptop Linux che mostra un prompt bash
fatmawati achmad zaenuri/Shutterstock.com

Di tutti i comandi Bash, il povero vecchio eval ha probabilmente la peggiore reputazione. Giustificato o solo cattiva stampa? Discutiamo dell'uso e dei pericoli di questi comandi Linux meno amati.

Dobbiamo parlare di eval

Usato con noncuranza, eval può portare a comportamenti imprevedibili e persino a insicurezze del sistema. A giudicare dai suoni, probabilmente non dovremmo usarlo, giusto? Beh, non proprio.

Si potrebbe dire qualcosa di simile sulle automobili. Nelle mani sbagliate, sono un'arma mortale. Le persone li usano nei raid arieti e come veicoli per la fuga. Dovremmo tutti smettere di usare le auto? No certo che no. Ma devono essere usati correttamente e da persone che sappiano guidarli.

Come lavorare con le variabili in Bash
CORRELATI Come lavorare con le variabili in Bash

Il solito aggettivo applicato a eval è "malvagio". Ma tutto si riduce a come viene utilizzato. Il comando eval raccoglie i valori da una o più variabili. Crea una stringa di comando. Quindi esegue quel comando. Ciò lo rende utile quando è necessario far fronte a situazioni in cui il contenuto di un comando viene derivato dinamicamente durante l'esecuzione dello script.

I problemi sorgono quando uno script viene scritto per utilizzare eval su una stringa che è stata ricevuta da qualche parte al di fuori dello script. Può essere digitato da un utente, inviato tramite un'API, taggato su una richiesta HTTPS o in qualsiasi altro luogo esterno allo script.

Se la stringa su cui eval non è stata derivata localmente ea livello di codice, esiste il rischio che la stringa contenga istruzioni dannose incorporate o altro input di formato errato. Ovviamente, non vuoi che eval esegua comandi dannosi. Quindi, per sicurezza, non utilizzare eval con stringhe generate esternamente o input dell'utente.

Primi passi con eval

Il comando eval è un comando della shell Bash integrato. Se Bash è presente, eval sarà presente.

eval concatena i suoi parametri in un'unica stringa. Utilizzerà un singolo spazio per separare gli elementi concatenati. Valuta gli argomenti e quindi passa l'intera stringa alla shell per l'esecuzione.

Creiamo una variabile chiamata wordcount .

 conteggio parole="wc -w raw-notes.md"

La variabile stringa contiene un comando per contare le parole in un file chiamato "raw-notes.md".

Possiamo usare eval per eseguire quel comando passandogli il valore della variabile.

 eval " $wordcount "

Utilizzo di eval con una variabile stringa per contare le parole in un file

Il comando viene eseguito nella shell corrente, non in una subshell. Possiamo facilmente mostrarlo. Abbiamo un breve file di testo chiamato "variables.txt". Contiene queste due righe.

 first=Come fare per
secondo=Geek

Useremo cat per inviare queste righe alla finestra del terminale. Quindi useremo eval per valutare un comando cat in modo che le istruzioni all'interno del file di testo vengano applicate. Questo imposterà le variabili per noi.

 gatto variabili.txt
eval "$(variabili cat.txt)"
eco $primo $secondo 

Accesso alle variabili impostate da eval nella shell corrente

Usando echo per stampare i valori delle variabili possiamo vedere che il comando eval viene eseguito nella shell corrente, non in una subshell.

Un processo in una subshell non può modificare l'ambiente della shell del genitore. Poiché eval viene eseguito nella shell corrente, le variabili impostate da eval sono utilizzabili dalla shell che ha lanciato il comando eval .

Nota che se usi eval in uno script, la shell che verrebbe modificata da eval è la subshell in cui è in esecuzione lo script, non la shell che lo ha lanciato.

CORRELATI: Come utilizzare i comandi cat e tac di Linux

Utilizzo di variabili nella stringa di comando

Possiamo includere altre variabili nelle stringhe di comando. Imposteremo due variabili per contenere numeri interi.

 num1=10 
num2=7

Creeremo una variabile per contenere un comando expr che restituirà la somma di due numeri. Ciò significa che dobbiamo accedere ai valori delle due variabili intere nel comando. Nota i backtick attorno all'istruzione expr .

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

Creeremo un altro comando per mostrarci il risultato expr .

 mostra = "eco"

Nota che non è necessario includere uno spazio alla fine della stringa echo , né all'inizio della stringa expr . eval si occupa di questo.

E per eseguire l'intero comando utilizziamo:

 eval $mostra $aggiungi 

Utilizzo di variabili nella stringa di comando

I valori delle variabili all'interno della stringa expr vengono sostituiti nella stringa da eval , prima che venga passata alla shell per essere eseguita.

CORRELATI: Come lavorare con le variabili in Bash

Accesso alle variabili all'interno delle variabili

È possibile assegnare un valore a una variabile, quindi assegnare il nome di tale variabile a un'altra variabile. Usando eval , puoi accedere al valore contenuto nella prima variabile, dal suo nome che è il valore memorizzato nella seconda variabile. Un esempio ti aiuterà a districarlo.

Copia questo script in un editor e salvalo come file chiamato "assign.sh".

 #!/bin/bash

title="Come fare per geek"
pagina web=titolo
comando = "eco"
eval $comando \${$pagina web}

Dobbiamo renderlo eseguibile con il comando chmod .

 chmod +x assign.sh 

Usare chmod per rendere eseguibile uno script

Dovrai farlo per tutti gli script che copi da questo articolo. Basta usare il nome dello script appropriato in ogni caso.

Quando eseguiamo il nostro script, vediamo il testo dalla variabile title anche se il comando eval sta usando la variabile webpage .

 ./assegna.sh 

Accesso al valore di una variabile dal suo nome memorizzato in un'altra variabile

Il simbolo del dollaro con escape " $ " e le parentesi graffe " {} " fanno sì che eval guardi il valore contenuto all'interno della variabile il cui nome è memorizzato nella variabile della webpage .

Utilizzo di variabili create dinamicamente

Possiamo usare eval per creare variabili in modo dinamico. Questo script è chiamato "loop.sh".

 #!/bin/bash

totale=0
label="Ciclo completato. Totale:"

per n in {1..10}
fare
  valuta x$n=$n
  echo "Ciclo" $x$n
  ((totale+=$x$n))
fatto

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

eco $etichetta $totale

Crea una variabile chiamata total che contiene la somma dei valori delle variabili che creiamo. Quindi crea una variabile stringa chiamata label . Questa è una semplice stringa di testo.

Faremo un ciclo 10 volte e creeremo 10 variabili chiamate x1 fino a x10 . L'istruzione eval nel corpo del ciclo fornisce la "x" e prende il valore del contatore del ciclo $n per creare il nome della variabile. Allo stesso tempo, imposta la nuova variabile sul valore del contatore di loop $n .

9 Esempi di loop for negli script Bash di Linux
CORRELATI 9 Esempi di cicli for negli script Bash di Linux

Stampa la nuova variabile nella finestra del terminale e quindi incrementa la variabile total con il valore della nuova variabile.

Al di fuori del ciclo, le 10 nuove variabili vengono stampate ancora una volta, tutte su una riga. Si noti che possiamo fare riferimento alle variabili anche con i loro nomi reali, senza utilizzare una versione calcolata o derivata dei loro nomi.

Infine, stampiamo il valore della variabile total .

 ./loop.sh 

Utilizzo di eval per creare dinamicamente variabili

CORRELATI: Primer: Bash Loops: for, while e until

Utilizzo di eval con array

Immagina uno scenario in cui hai uno script di lunga durata che esegue alcune elaborazioni per te. Scrive in un file di registro con un nome creato da un timestamp. Di tanto in tanto, avvierà un nuovo file di registro. Al termine dello script, se non si sono verificati errori, elimina i file di registro che ha creato.

Non vuoi che semplicemente rm *.log , vuoi solo che elimini i file di registro che ha creato. Questo script simula tale funzionalità. Questo è "clear-logs.sh".

 #!/bin/bash

dichiarare -a file di registro

conteggio file=0 
rm_string="eco"

funzione crea_file_log() {
  ((++conteggio file))
  nomefile=$(data +"%Y-%m-%d_%H-%M-%S").log
  logfiles[$filecount]=$nomefile
  echo $filecount "Creato" ${logfiles[$filecount]}
}

# corpo dello script. Qui viene eseguita un'elaborazione
# genera periodicamente un file di registro. Lo simuleremo
crea_file di registro
dormire 3
crea_file di registro
dormire 3
crea_file di registro
dormire 3
crea_file di registro

# ci sono dei file da rimuovere?
for ((file=1; file<=$contafile; file++))
fare
  # rimuovi il file di registro
  eval $rm_string ${file di registro[$file]} "cancellato..."
  file di registro[$file]=""
fatto

Lo script dichiara un array chiamato logfiles . Questo conterrà i nomi dei file di registro creati dallo script. Dichiara una variabile chiamata filecount . Questo conterrà il numero di file di registro che sono stati creati.

Dichiara anche una stringa chiamata rm_string . In uno script del mondo reale, questo conterrebbe il comando rm , ma stiamo usando echo in modo da poter dimostrare il principio in modo non distruttivo.

La funzione create_logfile() è dove viene chiamato ogni file di registro e dove verrebbe aperto. Stiamo solo creando il nome del file e fingendo che sia stato creato nel file system.

La funzione incrementa la variabile di filecount . Il suo valore iniziale è zero, quindi il primo nome file che creiamo viene memorizzato nella posizione uno nell'array. Questo è fatto apposta, come anche vedere più avanti.

Il nome del file viene creato utilizzando il comando date e l'estensione ".log". Il nome viene memorizzato nell'array nella posizione indicata da filecount . Il nome viene stampato nella finestra del terminale. In uno script del mondo reale, creeresti anche il file vero e proprio.

Come mettere in pausa uno script Bash con il comando Sleep di Linux
CORRELATI Come mettere in pausa uno script Bash con il comando di sospensione di Linux

Il corpo dello script viene simulato utilizzando il comando sleep . Crea il primo file di registro, attende tre secondi, quindi ne crea un altro. Crea quattro file di registro, distanziati in modo che i timestamp nei nomi dei file siano diversi.

Infine, c'è un ciclo che elimina i file di registro. Il file del contatore di loop è impostato su uno. Conta fino a includere il valore di filecount , che contiene il numero di file che sono stati creati.

Se filecount è ancora impostato su zero, perché non sono stati creati file di registro, il corpo del ciclo non verrà mai eseguito perché uno non è minore o uguale a zero. Ecco perché la variabile filecount è stata impostata su zero quando è stata dichiarata e perché è stata incrementata prima della creazione del primo file.

All'interno del ciclo, utilizziamo eval con la nostra rm_string non distruttiva e il nome del file che viene recuperato dall'array. Quindi impostiamo l'elemento dell'array su una stringa vuota.

Questo è ciò che vediamo quando eseguiamo lo script.

 ./clear-logs.sh 

Eliminazione di file i cui nomi sono archiviati in un array

Non è tutto male

Eval molto eval ha sicuramente i suoi usi. Come la maggior parte degli strumenti, usato incautamente è pericoloso e in più di un modo.

Se ti assicuri che le stringhe su cui funziona siano create internamente e non catturate da esseri umani, API o cose come richieste HTTPS, eviterai le insidie ​​principali.

CORRELATO: Come visualizzare la data e l'ora nel terminale Linux (e usarlo negli script Bash)