Come utilizzare eval negli script Bash di Linux
Pubblicato: 2022-08-22 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.
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 "
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
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
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
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
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
.
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
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.
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
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)