Nombres de variables dinámicas en Bash

Estoy confundido acerca de un script bash.

Tengo el siguiente código:

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

Quiero poder crear un nombre de variable que contenga el primer argumento del comando y que tenga el valor de, por ejemplo, la última línea de ls .

Entonces para ilustrar lo que quiero:

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

Entonces, ¿cómo debería definir / declarar $magic_way_to_define_magic_variable_$1 y cómo debería llamarlo dentro del script?

He intentado con eval , ${...} , \$${...} , pero todavía estoy confundido.

Use una matriz asociativa, con nombres de comando como claves.

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

Si no puede usar matrices asociativas (por ejemplo, debe admitir bash 3), puede usar declare para crear nombres dynamics de variables:

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

y use la expansión de parámetros indirectos para acceder al valor.

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

Ver BashFAQ: Indirection – Evaluación de variables indirectas / de referencia .

He estado buscando una forma mejor de hacerlo recientemente. El conjunto asociativo sonaba como excesivo para mí. Mira lo que he encontrado:

 suffix=bzz declare prefix_$suffix=mystr 

…y entonces…

 varname=prefix_$suffix echo ${!varname} 

El siguiente ejemplo devuelve el valor de $ name_of_var

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

Esto debería funcionar:

 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" 

Para matrices indexadas, puede hacer referencia a ellas de esta forma:

 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 

Las matrices asociativas se pueden referenciar de manera similar pero necesitan el interruptor -A en declare lugar de -a .

¡Guau, la mayoría de la syntax es horrible! Aquí hay una solución con una syntax más simple si necesita hacer una referencia indirecta de matrices:

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

Para casos de uso más simples, recomiendo la syntax descrita en la guía avanzada Bash-Scripting .

Quiero poder crear un nombre de variable que contenga el primer argumento del comando

archivo script.sh :

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

Prueba:

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

Según la help eval :

Ejecute argumentos como un comando de shell.


También puede usar la expansión indirecta Bash ${!var} , como ya se mencionó, sin embargo, no admite la recuperación de índices de matriz.


Para obtener más información o ejemplos, consulte BashFAQ / 006 sobre Indirection .

No conocemos ningún truco que pueda duplicar esa funcionalidad en POSIX o Bourne shells sin eval , que puede ser difícil de realizar de forma segura. Por lo tanto, considere esto un uso en su propio riesgo de pirateo .

Sin embargo, debe reconsiderar el uso de la indirección según las siguientes notas.

Normalmente, en scripts bash, no necesitará referencias indirectas en absoluto. En general, las personas ven esto como una solución cuando no entienden o no saben sobre Bash Arrays o no han considerado completamente otras funciones de Bash, como las funciones.

Poner los nombres de las variables o cualquier otra syntax bash dentro de los parámetros con frecuencia se hace incorrectamente y en situaciones inapropiadas para resolver problemas que tienen mejores soluciones. Viola la separación entre código y datos, y como tal lo pone en una pendiente resbaladiza hacia errores y problemas de seguridad. La indirección puede hacer que su código sea menos transparente y más difícil de seguir.

Según BashFAQ / 006 , puede usar la syntax de la cadena de read aquí para asignar variables indirectas:

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

Uso:

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

para el varname=$prefix_suffix , simplemente use:

 varname=${prefix}_suffix