linux - resueltos - ¿Cómo puedo generar nuevos nombres de variables sobre la marcha en un script de shell?
shell script linux español (5)
El problema
Está utilizando el valor de i como si fuera un índice de matriz. No lo es, porque SAMPLE1 y SAMPLE2 son variables separadas, no una matriz.
Además, al llamar a echo SAMPLE{$i}
, solo agrega el valor de i a la palabra "SAMPLE". La única variable que está eliminando referencias en esta declaración es $ i , por lo que obtuvo los resultados que obtuvo.
Maneras de abordar el problema
Hay dos formas principales de abordar esto:
- Desreferencia de varias etapas de una variable interpolada, a través de la expansión de variables integradas o indirectas .
- Iterando sobre una matriz, o usando i como un índice en una matriz.
Desreferencia con eval
Lo más fácil de hacer en esta situación es usar eval :
SAMPLE1=''1-first.with.custom.name''
SAMPLE2=''2-second.with.custom.name''
for (( i = 1; i <= 2; i++ )); do
eval echo /$SAMPLE${i}
done
Esto agregará el valor de i al final de la variable, y luego volverá a procesar la línea resultante, expandiendo el nombre de la variable interpolada (por ejemplo, SAMPLE1 o SAMPLE2 ).
Desreferencia con variables indirectas
La respuesta aceptada para esta pregunta es:
SAMPLE1=''1-first.with.custom.name''
SAMPLE2=''2-second.with.custom.name''
for (( i = 1; i <= 2; i++ ))
do
var="SAMPLE$i"
echo ${!var}
done
Esto es técnicamente un proceso de tres pasos. En primer lugar, asigna un nombre de variable interpolado a var , luego elimina el nombre de la variable almacenada en var y finalmente expande el resultado. Se ve un poco más limpio, y algunas personas se sienten más cómodas con esta sintaxis que con eval , pero el resultado es básicamente el mismo.
Iterando sobre una matriz
Puede simplificar tanto el ciclo como la expansión al iterar sobre una matriz en lugar de utilizar la interpolación variable. Por ejemplo:
SAMPLE=(''1-first.with.custom.name'' ''2-second.with.custom.name'')
for i in "${SAMPLE[@]}"; do
echo "$i"
done
Esto ha agregado beneficios sobre los otros métodos. Específicamente:
- No necesita especificar una prueba compleja de bucle.
- Usted accede a elementos de matriz individuales a través de la sintaxis $ SAMPLE [$ i] .
- Puede obtener la cantidad total de elementos con la expansión de variable $ {# SAMPLE} .
Equivalencia práctica para el ejemplo original
Los tres métodos funcionarán para el ejemplo dado en la pregunta original, pero la solución de matriz proporciona la mayor flexibilidad general. Elija la que mejor funcione para los datos que tiene a mano.
Intento generar nombres dinámicos var en un script de shell para procesar un conjunto de archivos con nombres distintos en un bucle de la siguiente manera:
#!/bin/bash
SAMPLE1=''1-first.with.custom.name''
SAMPLE2=''2-second.with.custom.name''
for (( i = 1; i <= 2; i++ ))
do
echo SAMPLE{$i}
done
Esperaría la salida:
1-first.with.custom.name
2-second.with.custom.name
pero tengo:
SAMPLE{1}
SAMPLE{2}
¿Es posible generar nombres de Var en la marcha?
Necesitas utilizar la Indirección Variable:
SAMPLE1=''1-first.with.custom.name''
SAMPLE2=''2-second.with.custom.name''
for (( i = 1; i <= 2; i++ ))
do
var="SAMPLE$i"
echo ${!var}
done
Desde la página de manual de Bash , bajo ''Expansión de parámetros'':
"Si el primer carácter del parámetro es un signo de exclamación (!), Se introduce un nivel de indirección variable. Bash usa el valor de la variable formada a partir del resto del parámetro como el nombre de la variable, esta variable se expande y luego el valor se usa en el resto de la sustitución, en lugar del valor del parámetro en sí. Esto se conoce como expansión indirecta ".
No es una respuesta independiente, solo una adición a la respuesta de Miquel, que no pude encajar bien en un comentario.
Puede llenar la matriz utilizando un bucle, el operador + = y un documento aquí también:
SAMPLE=()
while read; do SAMPLE+=("$REPLY"); done <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
En bash 4.0, es tan simple como
readarray SAMPLE <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
Puede usar eval
como se muestra a continuación:
SAMPLE1=''1-first.with.custom.name''
SAMPLE2=''2-second.with.custom.name''
for (( i = 1; i <= 2; i++ ))
do
eval echo /$SAMPLE$i
done
No por lo que yo sé, dijeron way @ johnshen64. Además, puedes resolver tu problema usando una matriz como esta:
SAMPLE[1]=''1-first.with.custom.name''
SAMPLE[2]=''2-second.with.custom.name''
for (( i = 1; i <= 2; i++ )) do
echo ${SAMPLE[$i]}
done
Tenga en cuenta que no necesita usar números como índices SAMPLE[hello]
funcionará igual de bien