bash nombres de variables dinámicas (variables)


12

Quiero crear dinámicamente una secuencia de cadenas mediante la manipulación de una matriz de elementos y crear algún procedimiento aritmético.

for name in FIRST SECOND THIRD FOURTH FIFTH; do
    $name = $(( $6 + 1 ))
    $name = "${$name}q;d"
    echo "${$name}"; printf "\n"
done

El resultado deseado sería el siguiente para $6iguales 0.

1q;d
2q;d
3q;d
4q;d
5q;d

Pero me sale este error

reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution
reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution
reel_first_part.sh: line 18: FIRST: command not found
reel_first_part.sh: line 19: ${$name}q;d: bad substitution

Supongo que es algo simple. Solía ​​funcionar cuando hacía algo como

FIRST=$(( $6 + 1 ))
FIRST="${FIRST}q;d"

1
¿Puedes explicarlo un poco mejor? Realmente no entiendo lo que estás tratando de hacer.
— neurona

¿Qué se supone que debe hacer `$ name = $ (($ 6 + 1))`?
— PSkocik

@PSkocik que esperaba hacerFIRST=$(( $6 + 1 ))
— giannis christofakis

Respuestas:


16

En primer lugar, no puede haber ningún espacio alrededor =en la declaración de variables en bash.

Para obtener lo que quieres puedes usar eval.

Por ejemplo, un script de muestra como el tuyo:

#!/bin/bash
i=0
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    eval "$name"="'$(( $i + 1 ))q;d'"
    printf '%s\n' "${!name}"
    i=$(( $i + 1 ))
done

Impresiones:

1q;d
2q;d
3q;d
4q;d
5q;d

Use con evalprecaución, algunas personas lo llaman malvado por alguna razón válida.

declare funcionaría también:

#!/bin/bash
i=0
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    declare "$name"="$(( $i + 1 ))q;d"
    printf '%s\n' "${!name}"
    i=$(( $i + 1 ))
done

también imprime:

1q;d
2q;d
3q;d
4q;d
5q;d

¿Para qué sirve el !signo de exclamación printf '%s\n' "${!name}"?
— giannis christofakis

1
Se llama expansión indirecta de la expansión de bashparámetros
— lea

1
Bash también tiene una alternativa más agradable a declare/ eval: printf -v varname '%fmt' args. Algunas funciones internas de finalización de bash lo usan para llamar por referencia. (pase el nombre de una variable para almacenar).
— Peter Cordes

Nota: El uso declaresolo establece la variable en el ámbito local, mientras que el evalenfoque la establece globalmente.
— usuario

11

Si desea hacer referencia a una variable bash mientras tiene el nombre almacenado en otra variable, puede hacerlo de la siguiente manera:

$ var1=hello
$ var2=var1
$ echo ${!var2}
hello

Usted almacena el nombre de la variable a la que desea acceder, por ejemplo, var2 en este caso. Luego accedes a él con ${!<varable name>}donde <variable name>hay una variable que contiene el nombre de la variable a la que deseas acceder.


Hay una forma portátil con eval var=\$$holderpero evales peligroso!
— gavenkoa

1
index=0;                                                                                                                                                                                                           
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    name=$(($index + 1))
    echo "${name}q;d"
    index=$((index+1))
done

¿Es eso lo que estás intentando?


1

Lo que obtengo de su código y su salida deseada (corríjame si me equivoco):
No se usan los nombres de variable "PRIMERO" / "SEGUNDO" / ..., solo necesita un bucle con un índice ... .

Esto hará el trabajo:

for i in {1..5} ; do echo $i"q;d" ; done


Sí, tienes razón, excepto que además quiero hacer una función aritmética con una variable.
— giannis christofakis

¿Puedes dar un ejemplo de esta función aritmética? ¿Necesita el nombre de la variable (como "TERCERO") o solo el valor del índice?
— csny

SUM=$(($6 + $i)); echo $SUM"q;d", Veo lo que estaba haciendo mal.
— giannis christofakis
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.