bash dynamiczne (zmienne) nazwy zmiennych

12

Chcę dynamicznie tworzyć sekwencję ciągów, manipulując tablicą elementów i tworząc procedurę arytmetyczną.

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

Wynik pożądania byłby poniżej dla $6równości 0.

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

Ale dostaję ten błąd

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

Myślę, że to coś prostego. Kiedyś coś działało

FIRST=$(( $6 + 1 ))
FIRST="${FIRST}q;d"
giannis christofakis
źródło
1
Czy możesz to trochę lepiej wyjaśnić. Naprawdę nie rozumiem, co próbujesz zrobić.
neuron
Co powinno zrobić `$ name = $ ((6 $ + 1))`?
PSkocik,
@PSkocik Miałem nadziejęFIRST=$(( $6 + 1 ))
giannis christofakis,

Odpowiedzi:

16

Przede wszystkim nie może być żadnej przestrzeni =w deklaracji zmiennej w bash.

Aby uzyskać to, czego chcesz, możesz użyć eval.

Na przykład przykładowy skrypt jak twój:

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

Wydruki:

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

Używaj evalostrożnie, niektórzy nazywają to złem z jakiegoś ważnego powodu.

declare też by działał:

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

drukuje również:

1q;d
2q;d
3q;d
4q;d
5q;d
heemayl
źródło
Do czego służy !wykrzyknik printf '%s\n' "${!name}"?
giannis christofakis,
1
Nazywa się to pośrednim rozszerzaniem rozszerzania bashparametrów.
Przeczytaj
1
Bash ma również alternatywę ładniejszy declare/ eval: printf -v varname '%fmt' args. Niektóre funkcje wewnętrzne kończące bash używają tego do wywołania przez referencję. (przekaż nazwę zmiennej, w której chcesz zapisać).
Peter Cordes,
Uwaga: Użycie declaretylko ustawia zmienną w zasięgu lokalnym, podczas gdy evalpodejście ustawia ją globalnie.
użytkownik
11

Jeśli chcesz odwoływać się do zmiennej bash, zachowując nazwę w innej zmiennej, możesz to zrobić w następujący sposób:

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

W tym przypadku przechowujesz nazwę zmiennej, do której chcesz uzyskać dostęp, powiedzmy var2. Następnie uzyskujesz do niego dostęp, ${!<varable name>}gdzie <variable name>jest zmienna zawierająca nazwę zmiennej, do której chcesz uzyskać dostęp.

Eric Renouf
źródło
Jest przenośny sposób, eval var=\$$holderale evaljest niebezpieczny!
gavenkoa,
1
index=0;                                                                                                                                                                                                           
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    name=$(($index + 1))
    echo "${name}q;d"
    index=$((index+1))
done

Czy tego właśnie próbujesz?

neuron
źródło
1

Co otrzymuję z twojego kodu i pożądanych danych wyjściowych (popraw mnie, jeśli się mylę):
Nie używa się nazw zmiennych „FIRST” / „SECOND” / ..., wystarczy pętla z indeksem. .

Spowoduje to wykonanie zadania:

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

csny
źródło
Tak, masz rację, tyle że dodatkowo chcę wykonać funkcję arytmetyczną ze zmienną.
giannis christofakis,
Czy możesz podać przykład tej funkcji arytmetycznej? Czy potrzebujesz do tego nazwy zmiennej (np. „TRZECIA”), czy tylko wartości indeksu?
cny
SUM=$(($6 + $i)); echo $SUM"q;d", Widzę, co robiłem źle.
giannis christofakis,