Standard1988
Anmeldungsdatum: 28. Dezember 2010
Beiträge: 87
|
Hallo Zusammen, ich habe ein File (list.lst) mit mehreren Arrays: | TEST_A=(
'1a'
'2a'
'3a'
)
TEST_B=(
'1b'
'2b'
'3b'
)
|
Jetzt möchte ich alle Elementen von allen Arrays über eine Forschleife in einem Script verarbeiten möchte: | #!/bin/bash
LST=list.lst
for i in `grep "^.*.=" $LST | cut -f1 -d"="`;
do
for tag in ${i[*]};
do
echo $tag
done
done
|
Ich bekomme als Ergebnis durch das echo dies: TEST_A TEST_B Es sollte aber folgendes herauskommen: 1a 2a 3a 1b 2b 3b Habt ihr eine Idee? Viele Grüße lnix
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 10984
Wohnort: München
|
Wenn man die Namen der definierten Arrays eindeutig in den Dateien erkennen kann (und deren Namen keine Variablen überschreiben, die sonst im Skript benötigt werden), könnte man die Datei mit den Arrays sourcen und dann über die gefundenen Definitonen für die Arrays iterieren:
| ##!/bin/bash
LST="list.lst"
source "$LST"
for i in $(grep -Po "^\w+(?=\=)" "$LST"); do # Wir suchen nach Zeichenketten am Zeilenanfang ohne Whitespace, die von einem "=" gefolgt werden
eval current_array=( '"${'$i'[@]}"' ) # hässlicher Trick, um über den String in der Variable $i an den Inhalt des eingelesenen Array zu kommen
for element in ${current_array[@]}; do
echo $element
done
done
|
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 12536
|
Man braucht auf jeden Fall eval . | source "$1"
for var in $(sed -ne 's#^\([^=]\+\)=.*#\1#p' "$1"); do
eval "printf '%s\\n' \"\${$var[@]}\""
done
|
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2503
|
Hübsch wird das alles nicht und ich sehe auch keinen Weg, wie du um ein
„eval “ herumkommen könntest. Hier nochmal eine andere Strategie. Er lässt sich mit „set “ alle
Shell-Variablen anzeigen und filtert dann die Arrays heraus. Das macht
er vor und nach dem Sourcen der Liste. „comm “ kann dann die neu
dazugekommenen Arraynamen herausfischen. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #!/bin/bash
arrays_before=$(set | sed -rn 's/^([_a-zA-Z0-9]+)=\(.*/\1/p')
source liste
arrays_after=$(set | sed -rn 's/^([_a-zA-Z0-9]+)=\(.*/\1/p')
arrays_new=$(comm -3 <(echo "$arrays_before") <(echo "$arrays_after"))
for i in $arrays_new
do
# Bash-interne Variable, die durch die Pipeline mit set/sed zustande
# kam.
[[ "$i" == PIPESTATUS ]] && continue
# Erzeugt das neue Array "arr", das mit den Elementen (nicht jedoch
# den Keys, falls welche gesetzt wären!) befüllt wird.
eval arr=(\"\${$i[@]}\")
for j in "${arr[@]}"
do
echo "<$i>: <$j>"
done
done
|
|
D630
Anmeldungsdatum: 24. Juli 2013
Beiträge: 329
|
1
2
3
4
5
6
7
8
9
10
11
12 | fn ()
for a
do
typeset -a 'A=("${'"${a}"'[@]}")'
for aa in "${A[@]}"
do
echo "$aa"
done
done
source LST
fn ${!TEST*}
|
:
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17433
Wohnort: Berlin
|
| sed "/[()].*/d;s/'//g;/^$/d" test.lst
1a
2a
3a
1b
2b
3b
|
Alles mit runden Klammern löschen (d=delete) Apostrophe ersetzen durch nix (substitute) leere Zeilen (Zeilenanfang ^, gefolgt von Zeilenende $) löschen.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
... sowas ist aber von hinten durch die Brust ins Auge !
Du musst jemanden haben, der Dir die Zeilen zwischen den Klammern einsammelt und daraus jeweils ein Array macht. Das kann z.B. sed sein: track@track:~$ sed -n '/(/,/)/ H; /)/ {s/.*//; x; s/\n/ /gp}' test_ab
TEST_A=( '1a' '2a' '3a' )
TEST_B=( '1b' '2b' '3b' ) Dann kannst Du den ganzen Kram auch source n: track@track:~$ . <(sed -n '/(/,/)/ H; /)/ {s/.*//; x; s/\n/ /gp}' test_ab)
track@track:~$ echo "${TEST_A[0]} .. ${TEST_A[1]} ... ${TEST_A[2]} und B: ${TEST_B[0]}"
1a .. 2a ... 3a und B: 1b - Du siehst, dass dann auch alles hübsch als Shell-Array vorliegt.
Aber ehrlich gesagt: sowas macht man eigentlich nicht ! LG, track
|
D630
Anmeldungsdatum: 24. Juli 2013
Beiträge: 329
|
Neben Meta-Abarbeit des Sourcefiles und direktes Ansprechen der Array-Namen kommen mir noch in den Sinn: manuell ein Meta-Array erstellen mit den Namen der normalen Arrays declare -ap benutzen und parsen
zu jedem Array eine namref mit ähnlichem Namen erstellen und dann declare -np benutzen oder testen mit [[ -n ]] alle Arrays in Funktionen einbetten und declare -f benutzen
Ein "kreatives" Beispiel: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | typeset -A Arrays
def ()
{
typeset a="$_"
Arrays[${a%%=*}]=${a#*=}
. <(echo "$a")
}
: TEST_A="(
'1a'
'2a'
'3a'
)"
def
: TEST_B="(
'1b'
'2b'
'3b'
)"
def
|
Und dann: | for _a in "${!Arrays[@]}"
do
typeset -a 'a=("${'"${_a}"'[@]}")'
for __a in "${a[@]}"
do
echo "$__a"
done
done
|
Edit:
|
TausB
Anmeldungsdatum: 26. November 2009
Beiträge: 1536
Wohnort: Terra incognita
|
Mein Vorschlag ohne eval (Grüße an rklm und Vain ☺):
| #!/bin/bash
LST="list.lst"
source "$LST"
for var in $(sed -ne 's#^\([^=]\+\)=.*#\1#p' "$LST"); do
array="$var[@]"
for x in ${!array}; do
echo "${x}"
done
done
|
|
D630
Anmeldungsdatum: 24. Juli 2013
Beiträge: 329
|
TausB schrieb: Mein Vorschlag ohne eval (Grüße an rklm und Vain ☺):
| #!/bin/bash
LST="list.lst"
source "$LST"
for var in $(sed -ne 's#^\([^=]\+\)=.*#\1#p' "$LST"); do
array="$var[@]"
for x in ${!array}; do
echo "${x}"
done
done
|
Jao. Ich halte trotzdem mal dagegen: 1) Man weiß ja nicht genau, was in der for-Schleife alles passieren soll. Auf Indizes kann jetzt nicht mehr zugegriffen werden; daher müsste dann doch ein array2=("${!array}") folgen?! – 2) Die Syntax kann von einer Version auf die nächste verschwinden. Siehe zum gesamtem Komplex BashFAQ/006, Suche: "risk hack"
|
TausB
Anmeldungsdatum: 26. November 2009
Beiträge: 1536
Wohnort: Terra incognita
|
D630 schrieb: 2) Die Syntax kann von einer Version auf die nächste verschwinden. Siehe zum gesamtem Komplex BashFAQ/006, Suche: "risk hack"
Nutze ich bereits seit Jahren - natürlich kann ich nicht in die Zukunft gucken, aber Updates sind hier doch recht überschaubar. PS: Warum hast Du dann selbst:
...
for _a in "${!Arrays[@]}"
...
vorgeschlagen? Abgesehen davan, dass diese Konstrukt (bei mir) überhaupt nicht funktioniert.
|
D630
Anmeldungsdatum: 24. Juli 2013
Beiträge: 329
|
TausB schrieb: PS: Warum hast Du dann selbst:
...
for _a in "${!Arrays[@]}"
...
vorgeschlagen? Abgesehen davan, dass diese Konstrukt (bei mir) überhaupt nicht funktioniert.
: Moment, das Vorgehen besteht ja aus zwei Schritten: a) an die Namen der indizierten Arrays herankommen und b) diese Arrays später in einer for-Loop benutzen. Dein Vorschlag, der ohne eval auskommt, bezieht sich auf b); für a) benutzt Du sed. Das in den BashFAQ als "Hack" Beschriebene ist nicht die Indirection an sich, sondern sie zu benutzen, um an Arrays heranzukommen, obwohl sie eigentlich für Skalare gedacht ist. Gemeint ist also array="$var[@]" . Hack hin oder her, unter gleichbleibenden Bedingungen kann man es ja machen; die Frage ist ja eher, ob in Schritt b) auf die Indizes zugegriffen werden können sollte. Wenn ja, müsste Dein Vorschlag ja noch erweitert werden (wenn es weitere Wege gibt, her damit!): | for var in wordlist; do
array="$var[@]"
array2=("${!array}")
for x in ${array2[@]}; do
echo "${x}"
done
done
|
Hier wird ein array2 gebraucht; Du kannst es direkt bekommen und auf die Indirection verzichten: | for var in wordlist; do
# eval 'array2=("${'"${var}"'[@]}")'
typeset -a 'array2=("${'"${var}"'[@]}")'
for x in ${array2[@]}; do
echo "${x}"
done
done
|
Mein for _a in "${!Arrays[@]}" bezieht sich auf meinen zweiten Vorschlag für Schritt a), wobei Arrays ein assoc. Array ist (was es nicht sein müsste).
|
D630
Anmeldungsdatum: 24. Juli 2013
Beiträge: 329
|
Statt einzelne Zwischen-Arrays kann man auch gleich ein einzelnes bauen (Idee: von geirha in bash@freenode): | source FILE
typeset -a "A=( $(printf '"${%s[@]}" ' "${!TEST_@}") )"
for a in "${A[@]}"
do
echo "$a"
done
|
:
|