J'essaie de générer des noms var dynamiques dans un script Shell pour traiter un ensemble de fichiers avec des noms distincts dans une boucle comme suit:
#!/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
Je m'attendrais à la sortie:
1-first.with.custom.name
2-second.with.custom.name
mais j'ai:
SAMPLE{1}
SAMPLE{2}
Est-il possible de générer des noms var à la volée?
Vous devez utiliser l'indirection 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
Depuis la page de manuel Bash , sous 'Expansion des paramètres':
"Si le premier caractère du paramètre est un point d'exclamation (!), Un niveau d'indirection de variable est introduit. Bash utilise la valeur de la variable formée à partir du reste du paramètre comme nom de la variable; cette variable est ensuite développée et la valeur est utilisée dans le reste de la substitution, plutôt que la valeur du paramètre lui-même. C'est ce qu'on appelle l'expansion indirecte. "
Vous utilisez la valeur de i comme s'il s'agissait d'un index de tableau. Ce n'est pas le cas, car SAMPLE1 et SAMPLE2 sont des variables distinctes, pas un tableau.
De plus, lorsque vous appelez echo SAMPLE{$i}
vous ajoutez uniquement la valeur i au mot "SAMPLE". La seule variable que vous déréférencer dans cette instruction est $ i , c'est pourquoi vous avez obtenu les résultats que vous avez obtenus.
Il existe deux façons principales de résoudre ce problème:
La chose la plus simple à faire dans cette situation est d'utiliser 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
Cela ajoutera la valeur de i à la fin de la variable, puis retraitera la ligne résultante, développant le nom de la variable interpolée (par exemple SAMPLE1 ou SAMPLE2).
La réponse acceptée pour cette question est:
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
Il s'agit techniquement d'un processus en trois étapes. Tout d'abord, il attribue un nom de variable interpolé à var, puis déréférence le nom de variable stocké dans var, et enfin développe le résultat. Cela semble un peu plus propre, et certaines personnes sont plus à l'aise avec cette syntaxe qu'avec eval, mais le résultat est en grande partie le même.
Vous pouvez simplifier la boucle et l'expansion en itérant sur un tableau au lieu d'utiliser l'interpolation variable. Par exemple:
SAMPLE=('1-first.with.custom.name' '2-second.with.custom.name')
for i in "${SAMPLE[@]}"; do
echo "$i"
done
Cela a ajouté des avantages par rapport aux autres méthodes. Plus précisément:
Les trois méthodes fonctionneront pour l'exemple donné dans la question d'origine, mais la solution de tableau offre la flexibilité la plus globale. Choisissez celui qui fonctionne le mieux pour les données dont vous disposez.
Pas autant que je sache, Ils ont dit @ johnshen64. En outre, vous pouvez résoudre votre problème en utilisant un tableau comme celui-ci:
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
Notez que vous n'avez pas besoin d'utiliser des nombres comme index SAMPLE[hello]
fonctionnera aussi bien
Vous pouvez utiliser eval
comme indiqué ci-dessous:
SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'
for (( i = 1; i <= 2; i++ ))
do
eval echo \$SAMPLE$i
done
Pas une réponse autonome, juste un ajout à la réponse de Miquel que je ne pouvais pas bien intégrer dans un commentaire.
Vous pouvez remplir le tableau à l'aide d'une boucle, de l'opérateur + = et d'un document ici également:
SAMPLE=()
while read; do SAMPLE+=("$REPLY"); done <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF
Dans bash 4.0, c'est aussi simple que
readarray SAMPLE <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF