ubuntuusers.de

Variable in Variable (Shell)

Status: Gelöst | Ubuntu-Version: Ubuntu 14.04 (Trusty Tahr)
Antworten |

king_siggi

Anmeldungsdatum:
24. November 2015

Beiträge: Zähle...

Guten Tag,

ich versuche derzeit in einem Skript eine Variable "Variable/ Dynamisch" aufzurufen. Ich versuche das mal zu veranschaulichen.

1
2
3
4
5
6
7
8
zaehler=1
inhouse_name_count="$(echo "SELECT count(*) FROM inhouse" | mysql --skip-column-names -u **** -p***** ****)";
inhouse_name_count1=$(expr $inhouse_name_count + 1)
while [ $zaehler -lt $inhouse_name_count1 ]
do
eval inhouse_name${zaehler}="$(echo "select server_name from inhouse WHERE id = $zaehler" | mysql --skip-column-names -u **** -p***** ****)";
zaehler=$(($zaehler+1))
done

Das Ergebnis hiervon ist das ich bspw. die Variable $inhouse_name13 aufrufen kann und dann den entsprechen wert aus der Datenbank erhalte.

Nun zu dem Zweiten Teil:

1
2
3
4
5
6
7
8
zaehler=1
dir_count="$(echo "SELECT count(*) FROM inhouse" | mysql --skip-column-names -u **** -p***** ****)";
dir_count1=$(expr $dir_count + 1)
while [ $zaehler -lt $dir_count1 ]
do
echo "inhouse_name"$zaehler
zaehler=$(($zaehler+1))
done

Das Ergebnis hiervon soll! sein das ich nun nacheinander jeden einzelnen Wert ausgegeben bekomme. Also den wert der hinter $inhouse_name1; $inhouse_name2 und so weiter steht. Logischer weise bekomme ich mit dem Obigen Code als ausgabe nur "inhouse_name1" als string geliefert, ich jedoch brauche den Wert der hinter der Variable "inhouse_name1" steht.

Ich weiß das ganze ist etwas schwer zu Erklären/ Verstehen, aber ich hoffe das Ihr damit wisst was ich meine und mir vielleicht einen Rat geben könnt wie man dies Lösen kann.

Danke im Voraus

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Hi Majestät,

erstmal herzlich willkommen hier auf dem Forum !

Das was Du da machen willst, ist eigentlich ein ganz typischer Fall für Arrays.

Aber gut, wenn Du es unbedingt willst, dann kannst Du es mit eval hintricksen:

track@track:~$ var1=A
track@track:~$ var2=B
track@track:~$ var3=C
track@track:~$ for i in 1 2 3; do x=var$i; echo $x;  eval echo \$$x ; done
var1
A
var2
B
var3
C 

Allerdings ist eval immer so eine Sache, weil es ein Sicherheitsleck darstellt. (→ Daten werden plötzlich ausführbar !!)

LG,

track

senden9

Avatar von senden9

Anmeldungsdatum:
8. Februar 2010

Beiträge: 965

Wohnort: Österreich

Hallo,

Ich glaube du versuchst hier ein Array nach zubauen.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17622

Wohnort: Berlin

Mit mysql kenne ich mich nicht aus, aber 2 Dinge lassen sich wohl auch so sagen:

a)

1
2
3
4
5
dir_count1=$(expr $dir_count + 1)
while [ $zaehler -lt $dir_count1 ]
do
echo "inhouse_name"$zaehler
zaehler=$(($zaehler+1))

Bei dir_count1 und zaehler benutzt Du 2 unterschiedliche Formen arithmetischer Aufrufe. Der zweite ist billiger und der empfohlene. Allerdings ist das Dollarsymbol vor dem Namen in arithmetischen Ausdrücken überflüssig:

1
2
3
zaehler=$((zaehler+1))
# geht auch und noch kuerzer
((zaehler+=1))

Problem 2, indizierte Variablen. Das geht am besten mit Arrays.

1
2
3
4
5
declare -a inhouse_name 
inhouse_name=($(seq 1 $dir_count1)) 
inhouse_name[4]=9
inhouse_name[$foo]=$bar
echo ${inhouse_name[@]}

TausB

Avatar von TausB

Anmeldungsdatum:
26. November 2009

Beiträge: 1570

Wohnort: Terra incognita

track schrieb:

Allerdings ist eval immer so eine Sache, weil es ein Sicherheitsleck darstellt. (→ Daten werden plötzlich ausführbar !!)

Weil das so ist, man aber trotzdem evtl. kein array nutzen möchte, geht es auch so:

1
2
3
4
5
6
7
8
var1=A
var2=B
var3=C

for i in 1 2 3 ; do
var="var$i"
echo ${!var}
done

Diese Variante wird gern übersehen. 😉

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Die Substring Expansion dafür zu nehmen ist hübsch !
... ich hatte sie tatsächlich nicht auf dem Schirm, wahrscheinlich weil die mit ihrem exotischen Flair immer unter "ferner liefen" verschwindet.

Ist aber auf jeden Fall die Lösung der Wahl !

LG, und besonderen Dank für den Tip,

track

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17622

Wohnort: Berlin

Die habe ich auch kürzlich erst gesehen, und mir nicht gemerkt wie es geht.

Ich weiß auch nicht wie ich mir merken soll, wie ich es in der Manpage wiederfinde. Substring Expansion, ja, kann ich mir nicht merken. ☺

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13213

track schrieb:

Die Substring Expansion dafür zu nehmen ist hübsch !
... ich hatte sie tatsächlich nicht auf dem Schirm, wahrscheinlich weil die mit ihrem exotischen Flair immer unter "ferner liefen" verschwindet.

Geht mir auch so. Ich skripte soweit möglich auch immer mit der sh:

Ist aber auf jeden Fall die Lösung der Wahl !

Soweit ich das sehe, gibt es die in der sh nicht und die ist auch nicht POSIX-kompatibel. Wenn man also sowieso schon eine bash, zsh o.ä. benötigt, erscheint mir ein Array das deutlich bessere Mittel der Wahl.

Es gibt noch ein paar grundsätzliche Anmerkungen zur Verfahrensweise:

  • Es ist sehr ineffizient, für jede Zeile einen SELECT abzusetzen.

  • Das Verfahren erfasst nur wirklich alle Datensätze, wenn es keine Lücken bei der Spalte "id" gibt.

  • Die Ausgabe von echo nach mysql zu füttern ist auch überflüssig, da man über die Option "-e" ein SQL-Statement absetzen kann (sagt zumindest die Manpage).

Man müsste wissen, was mit den Daten weiters passieren soll, um eine sinnvolle Alternative anzubieten. Wenn man diese Variablen so definieren will, könnte dies gehen:

1
eval "$(mysql --skip-column-names -u **** -p***** **** -e "select concat('inhouse_name', id, '=', server_name) from inhouse")"

king_siggi

(Themenstarter)

Anmeldungsdatum:
24. November 2015

Beiträge: 2

Guten Tag,

so nach dem ich mir noch einige Zeit mit allen tipps den Kopf darüber zerbrochen habe bin ich nun auf die Lösung gekommen. Erstmal zum Ergebnis:

1
2
3
4
5
6
7
8
9
zaehler=1
dir_count="$(echo "SELECT count(*) FROM inhouse" | mysql --skip-column-names -u **** -p***** ****)";
dir_count1=$(expr $dir_count + 1)
while [ $zaehler -lt $dir_count1 ]
do
inhouse_name="inhouse_name"$zaehler
echo ${!inhouse_name}
((zaehler+=1))
done

Die Idee mit einem Array zu arbeiten fand ich sehr gut, doch ich muss zugeben das ich bisher nie damit gearbeitet hatte und mich damit erstmal kurz im allgemeinen beschäftigt habe. Nun bin ich mit dem Array aber auf das selbe ergebnis gekommen,- immer nur zb. "$inhouse_name12" aber nicht die auflösung von "$inhouse_name12".

Um noch einmal den Punkt anzusprechen was mit den Daten passieren soll, folgendes:

  • Ich vereinbare am Anfang jede menge Variablen.

  • Nun setze ich im weiteren verlauf all diese Variablen durch schleifen Durchläufe zusammen um bestimmte Aktionen

aufzurufen.

In dem Code den ich hier gepostet habe wäre die nachfolgende Aktion diese:

1
mkdir -p /hier/ist/der/pfad/${!inhouse_name}

Es soll also in diesem beispiel jeder Wert genommen werden um einen Ordner mit dem entsprechenden Namen anzulegen. Ich hoffe ihr konntet mir hier folgen und ich hab es ausführlich genug beschrieben.

Vielen Dank für eure Unterstützung LG Siggi ☺

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Wenn Du bisher noch nie mit Arrays was gemacht hast, mag es etwas Eingewöhnung brauchen, ist aber im Grunde ganz simpel:
Du hast eine Variable mit beliebig vielen Feldern, die Du über den [Index] ansprechen kannst:

track@track:~$ x=( A B C D E )                                          # die 5 Zellen werden zusammen am Stück gefüllt
track@track:~$ for i in {0..4} ; do   echo "$i:  ${x[i]}";   done       # und in einer Schleife Index und Inhalt einzeln ausgegeben:
0:  A
1:  B
2:  C
3:  D
4:  E 

Zum genauen Verständnis lies bitte oben meinen Link dazu nochmal nach !

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13213

king_siggi schrieb:

so nach dem ich mir noch einige Zeit mit allen tipps den Kopf darüber zerbrochen habe bin ich nun auf die Lösung gekommen. Erstmal zum Ergebnis: [...]

Das ist aber immer noch eine Schleife. Das ist ineffizient und unnötig.

In dem Code den ich hier gepostet habe wäre die nachfolgende Aktion diese:

1
mkdir -p /hier/ist/der/pfad/${!inhouse_name}

Es soll also in diesem beispiel jeder Wert genommen werden um einen Ordner mit dem entsprechenden Namen anzulegen.

Dann kannst Du Dein ganzes Skript in einen Einzeiler verwandeln:

1
mysql -B --skip-column-names -u **** -p***** **** -e "select concat('mkdir /hier/ist/der/pfad/', server_name) from inhouse" | sh

oder, etwas robuster

1
2
mysql -B --skip-column-names -u **** -p***** **** \
  -e "select concat('mkdir ''/hier/ist/der/pfad/', server_name, ''';') from inhouse where server_name not is null" | sh

Ich hoffe ihr konntet mir hier folgen und ich hab es ausführlich genug beschrieben.

Ja, ich denke schon.

Antworten |