noms de variables dynamiques bash (variables)

12

Je veux créer dynamiquement une séquence de chaînes en manipulant un tableau d'éléments et créer une procédure arithmétique.

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

Le résultat souhaité serait le ci-dessous pour les $6égaux 0.

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

Mais je reçois cette erreur

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

Je suppose que c'est quelque chose de simple. Ça fonctionnait quand je faisais quelque chose comme

FIRST=$(( $6 + 1 ))
FIRST="${FIRST}q;d"
giannis christofakis
la source
1
Pouvez-vous l'expliquer un peu mieux. Je ne comprends pas vraiment ce que vous essayez de faire.
neurone
Qu'est-ce que `$ name = $ (($ 6 + 1))` est censé faire?
PSkocik
@PSkocik J'espérais faireFIRST=$(( $6 + 1 ))
giannis christofakis

Réponses:

16

Tout d'abord, il ne peut y avoir d'espace autour =de la déclaration de variable dans bash.

Pour obtenir ce que vous voulez, vous pouvez l’utiliser eval.

Par exemple, un exemple de script comme le vôtre:

#!/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

Tirages:

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

Utilisez evalavec prudence, certaines personnes l'appellent mal pour une raison valable.

declare fonctionnerait aussi:

#!/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

imprime également:

1q;d
2q;d
3q;d
4q;d
5q;d
heemayl
la source
À quoi sert le !point d'exclamation printf '%s\n' "${!name}"?
giannis christofakis
1
C'est ce qu'on appelle l'expansion indirecte de l'expansion des bashparamètres
lire
1
Bash dispose également d' une plus belle alternative à declare/ eval: printf -v varname '%fmt' args. Certaines fonctions internes de complétion de bash l'utilisent pour l'appel par référence. (passez le nom d'une variable dans laquelle stocker).
Peter Cordes
Remarque: L'utilisation declaredéfinit uniquement la variable dans la portée locale, tandis que l' evalapproche la définit globalement.
utilisateur
11

Si vous souhaitez référencer une variable bash tout en ayant le nom stocké dans une autre variable, vous pouvez le faire comme suit:

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

Vous stockez le nom de la variable à laquelle vous souhaitez accéder dans, disons, var2 dans ce cas. Ensuite, vous y accédez avec ${!<varable name>}où se <variable name>trouve une variable contenant le nom de la variable à laquelle vous souhaitez accéder.

Eric Renouf
la source
Il y a moyen portable eval var=\$$holdermais evaldangereux!
gavenkoa
1
index=0;                                                                                                                                                                                                           
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    name=$(($index + 1))
    echo "${name}q;d"
    index=$((index+1))
done

C'est ça que vous essayez?

neurone
la source
1

Ce que j'obtiens de votre code et de votre sortie souhaitée (corrigez-moi si je me trompe):
Il n'y a pas d'utilisation des noms de variables "FIRST" / "SECOND" / ..., vous avez juste besoin d'une boucle avec un index .. .

Cela fera le travail:

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

csny
la source
Oui, vous avez raison, sauf que je veux en plus faire une fonction arithmétique avec une variable.
giannis christofakis
Pouvez-vous donner un exemple de cette fonction arithmétique? Avez-vous besoin du nom de variable (comme "TROISIÈME") pour cela ou simplement de la valeur d'index?
csny
SUM=$(($6 + $i)); echo $SUM"q;d", Je vois ce que je faisais mal.
giannis christofakis