Nomi di variabili dinamiche in Bash

Sono confuso su uno script di bash.

Ho il codice seguente:

function grep_search() { magic_way_to_define_magic_variable_$1=`ls | tail -1` echo $magic_variable_$1 } 

Voglio essere in grado di creare un nome di variabile contenente il primo argomento del comando e con il valore di es. L’ultima riga di ls .

Quindi per illustrare ciò che voglio:

 $ ls | tail -1 stack-overflow.txt $ grep_search() open_box stack-overflow.txt 

Quindi, come dovrei definire / dichiarare $magic_way_to_define_magic_variable_$1 e come dovrei chiamarlo all’interno dello script?

Ho provato l’ eval , ${...} , \$${...} , ma sono ancora confuso.

Utilizzare un array associativo, con i nomi dei comandi come chiavi.

 # Requires bash 4, though declare -A magic_variable=() function grep_search() { magic_variable[$1]=$( ls | tail -1 ) echo ${magic_variable[$1]} } 

Se non è ansible utilizzare array associativi (ad esempio, è necessario supportare bash 3), è ansible utilizzare declare per creare nomi di variabili dinamici:

 declare "magic_variable_$1=$(ls | tail -1)" 

e utilizzare l’espansione dei parametri indiretti per accedere al valore.

 var="magic_variable_$1" echo "${!var}" 

Vedi BashFAQ: Indirection: valutazione delle variabili indirette / di riferimento .

Ho cercato un modo migliore di farlo di recente. L’array associativo mi sembrava eccessivo. Guardate cosa ho trovato:

 suffix=bzz declare prefix_$suffix=mystr 

…e poi…

 varname=prefix_$suffix echo ${!varname} 

L’esempio seguente restituisce il valore di $ nome_di_var

 var=name_of_var echo $(eval echo "\$$var") 

Questo dovrebbe funzionare:

 function grep_search() { declare magic_variable_$1="$(ls | tail -1)" echo "$(tmpvar=magic_variable_$1 && echo ${!tmpvar})" } grep_search var # calling grep_search with argument "var" 

Per gli array indicizzati, puoi fare riferimento ad essi in questo modo:

 foo=(abc) bar=(def) for arr_var in 'foo' 'bar'; do declare -a 'arr=("${'"$arr_var"'[@]}")' # do something with $arr echo "\$$arr_var contains:" for char in "${arr[@]}"; do echo "$char" done done 

Gli array associativi possono essere referenziati in modo simile ma hanno bisogno che l’ -A declare invece di -a .

Wow, la maggior parte della syntax è orribile! Ecco una soluzione con una syntax più semplice se è necessario indirizzare gli array in modo indiretto:

 #!/bin/bash foo_1=("fff" "ddd") ; foo_2=("ggg" "ccc") ; for i in 1 2 ; do eval mine=( \${foo_$i[@]} ) ; echo ${mine[@]} ; done ; 

Per casi d’uso più semplici, raccomando la syntax descritta nella Guida avanzata di Bash-Scripting .

Voglio essere in grado di creare un nome di variabile contenente il primo argomento del comando

script.sh :

 #!/usr/bin/env bash function grep_search() { eval $1=$(ls | tail -1) } 

Test:

 $ source script.sh $ grep_search open_box $ echo $open_box script.sh 

Come da help eval :

Esegui argomenti come comando di shell.


Si può anche usare l’espansione indiretta di Bash ${!var} , come già accennato, ma non supporta il recupero degli indici di array.


Per ulteriori letture o esempi, controllare BashFAQ / 006 su Indirection .

Non siamo a conoscenza di alcun trucco che possa duplicare tale funzionalità nelle shell POSIX o Bourne senza eval , il che può essere difficile da fare in modo sicuro. Quindi, considera questo un uso a tuo rischio .

Tuttavia, dovresti considerare nuovamente l’uso di indirezione come da note seguenti.

Normalmente, in bash scripting, non avrai bisogno di riferimenti indiretti. Generalmente, le persone guardano a questo per una soluzione quando non capiscono o sanno di Bash Arrays o non hanno completamente considerato altre funzionalità di Bash come le funzioni.

L’inserimento di nomi di variabili o di qualsiasi altra syntax di bash all’interno dei parametri viene spesso eseguito in modo errato e in situazioni inappropriate per risolvere problemi con soluzioni migliori. Violare la separazione tra codice e dati e, in quanto tale, ti porta su una china scivolosa verso bug e problemi di sicurezza. L’indirazione può rendere il tuo codice meno trasparente e più difficile da seguire.

Come per BashFAQ / 006 , puoi usare read con la syntax delle stringhe qui per assegnare le variabili indirette:

 function grep_search() { read "$1" <<<$(ls | tail -1); } 

Uso:

 $ grep_search open_box $ echo $open_box stack-overflow.txt 

per il formato varname=$prefix_suffix , usa solo:

 varname=${prefix}_suffix