Bash dynamische (variable) Variablennamen

12

Ich möchte dynamisch eine Folge von Zeichenfolgen erstellen, indem ich ein Array von Elementen manipuliere und eine arithmetische Prozedur erstelle.

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

Das Wunschergebnis wäre für $6Gleichgestellte das Folgende 0.

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

Aber ich bekomme diesen Fehler

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

Ich denke, es ist etwas Einfaches. Früher hat es funktioniert, als ich so etwas gemacht habe

FIRST=$(( $6 + 1 ))
FIRST="${FIRST}q;d"
Giannis Christofakis
quelle
1
Kannst du es ein bisschen besser erklären? Verstehe nicht wirklich, was du versuchst zu tun.
Neuron
Was soll $ name = $ (($ 6 + 1)) tun?
PSkocik
@PSkocik Ich hatte gehofft zu tunFIRST=$(( $6 + 1 ))
Giannis Christofakis

Antworten:

16

Erstens darf =in der Variablendeklaration in kein Leerzeichen enthalten sein bash.

Um zu bekommen, was Sie wollen, können Sie verwenden eval.

Zum Beispiel ein Beispielskript wie das Ihre:

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

Drucke:

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

Verwenden Sie evalvorsichtig, rufen manche Leute es übel aus irgendeinem triftigen Grund.

declare würde auch funktionieren:

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

druckt auch:

1q;d
2q;d
3q;d
4q;d
5q;d
heemayl
quelle
Wofür ist das !Ausrufezeichen printf '%s\n' "${!name}"?
Giannis Christofakis
1
Die so genannte indirekte Erweiterung der bashParametererweiterung
read
1
Bash hat auch eine schönere Alternative zu declare/ eval: printf -v varname '%fmt' args. Einige interne Funktionen für die Bash-Vervollständigung verwenden diese Funktion als Referenz. (Übergeben Sie den Namen einer Variablen, in der gespeichert werden soll).
Peter Cordes
Hinweis: Wenn Sie declarenur verwenden, wird die Variable im lokalen Bereich festgelegt, während der evalAnsatz sie global festlegt.
Benutzer
11

Wenn Sie eine Bash-Variable referenzieren möchten, während der Name in einer anderen Variablen gespeichert ist, können Sie dies wie folgt tun:

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

In diesem Fall speichern Sie den Namen der Variablen, auf die Sie zugreifen möchten, beispielsweise in var2. Dann greifen Sie darauf zu, ${!<varable name>}indem Sie angeben, wo <variable name>sich eine Variable befindet, die den Namen der Variablen enthält, auf die Sie zugreifen möchten.

Eric Renouf
quelle
Es ist tragbar, eval var=\$$holderaber evalgefährlich!
Gavenkoa
1
index=0;                                                                                                                                                                                                           
for name in FIRST SECOND THIRD FOURTH FIFTH; do
    name=$(($index + 1))
    echo "${name}q;d"
    index=$((index+1))
done

Versuchen Sie das?

Neuron
quelle
1

Was ich von Ihrem Code und Ihrer gewünschten Ausgabe bekomme (korrigieren Sie mich, wenn ich falsch liege): Die
Variablennamen "FIRST" / "SECOND" / ... werden nicht verwendet, Sie benötigen nur eine Schleife mit einem Index. .

Das erledigt die Arbeit:

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

csny
quelle
Ja, Sie haben Recht, außer dass ich zusätzlich eine arithmetische Funktion mit einer Variablen ausführen möchte.
Giannis Christofakis
Können Sie ein Beispiel für diese Rechenfunktion geben? Benötigen Sie den Variablennamen (wie "THIRD") dafür oder nur den Indexwert?
csny
SUM=$(($6 + $i)); echo $SUM"q;d"Ich sehe, was ich falsch gemacht habe.
Giannis Christofakis