2012-04-02 4 views
5

Come posso inserire un array in loop? Mi piacerebbe fare qualcosa di simile:bash popola un array nel loop

declare -A results 

results["a"]=1 
results["b"]=2 

while read data; do 
results[$data]=1 
done 

for i in "${!results[@]}" 
do 
    echo "key : $i" 
    echo "value: ${results[$i]}" 
done 

Ma sembra che non posso aggiungere nulla a una matrice all'interno ciclo for. Perché?

+1

Quale versione di bash stai usando? – siride

risposta

13

Che cosa dovrebbe funzionare, supponendo che abbiate una versione di Bash che supporta gli array associativi per cominciare.

Se riesco a indovinare. . . stai eseguendo qualcosa del genere:

command_that_outputs_keys \ 
    | while read data; do 
     results[$data]=1 
    done 

? Quello è — è la parte del ciclo while di una pipeline? Se è così, allora che il problema è. Vedete, ogni comando in una pipeline riceve una copia dell'ambiente di esecuzione della shell. Quindi il ciclo while popolerà una copia della matrice results e al termine del ciclo while, la copia scompare.

A cura di aggiungere: Se questo è il problema, poi come glenn jackman punti in un commento, si può risolvere il problema utilizzando process substitution invece:

while read data; do 
    results[$data]=1 
done < <(command_that_outputs_keys) 

In questo modo, anche se riceveranno command_that_outputs_keys solo una copia dell'ambiente di esecuzione della shell (come prima), il ciclo while avrà l'ambiente principale originale, quindi può modificare l'array originale.

+4

+1 il modo per evitare la subshell è usare la sostituzione di processo: 'while ... done <<(comando qui)' –

+0

@glennjackman: Brilliant, grazie! Il mio primo pensiero era stato "usare invece la sostituzione del processo", ma il mio secondo pensiero era "oh, aspetta, sarebbe appena stato sostituito con un nome file, e" while "non saprebbe prendere il file come input". '<<(...)' ha senso ora che ne sono a conoscenza, ma non avrei mai immaginato che fosse permesso. Ho aggiornato la mia risposta. Grazie ancora! :-D – ruakh

1

che sembra funzionare bene:

$ cat mkt.sh 
declare -A results 

results["a"]=1 
results["b"]=2 

while read data; do 
    results[$data]=1 
done << EOF 
3 
4 
5 
EOF 

for i in "${!results[@]}" 
do 
    echo "key : $i" 
    echo "value: ${results[$i]}" 
done 

$ ./mkt.sh 
key : a 
value: 1 
key : b 
value: 2 
key : 3 
value: 1 
key : 4 
value: 1 
key : 5 
value: 1 
$ 

Ubuntu 11.10 qui, bash: GNU bash, la versione 4.2.10 (1) -release (x86_64-pc-linux-gnu).