Lettura di una stringa delimitata in un array in Bash


207

Ho una variabile che contiene una stringa delimitata da spazi:

line="1 1.50 string"

Voglio dividere quella stringa con spazio come delimitatore e archiviare il risultato in un array, in modo che:

echo ${arr[0]}
echo ${arr[1]}
echo ${arr[2]}

uscite

1
1.50
string

Da qualche parte ho trovato una soluzione che non funziona:

arr=$(echo ${line})

Se dopo eseguo le istruzioni echo sopra riportate, ottengo:

1 1.50 string
[empty line]
[empty line]

Ho anche provato

IFS=" "
arr=$(echo ${line})

con lo stesso risultato. Qualcuno può aiutare, per favore?


Vedi questa risposta su Unix & Linux Stack Exchange: Usare sed con herestring (<<<) e leggere -a . set -f; arr=($string); set +fsembra essere più veloce di read -r -a <<< $string.
codeforester

Risposte:


332

Per convertire una stringa in un array, utilizzare

arr=($line)

o

read -a arr <<< $line

È fondamentale non usare le virgolette poiché questo è il trucco.


7
e per fare un controllo di sanità mentale del tuo bellissimo nuovo array:for i in ${arr[@]}; do echo $i; done
Banjer,

5
o soloecho ${arr[@]}
Banjer,

13
Entrambi i modi possono fallire se $linecontiene personaggi sconvolgenti. mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}dà 3
Tino,

3
declare -a "arr=($line)"ignorerà i IFSdelimitatori all'interno delle stringhe tra virgolette
Dave,

4
@Tino No. Quando line='*', read -a arr <<<$linefunziona sempre, ma arr=($line)fallisce.
Johnny Wong,

39

Prova questo:

arr=(`echo ${line}`);

5
Nice - Questa soluzione funziona anche nella shell Z dove alcuni degli altri approcci sopra falliscono.
Keith Hughitt,

Funziona, potresti spiegare perché funziona?
smartwjw,

2
Nota: questo non funziona neanche quando la riga contiene '*', comeline='*'
Johnny Wong,

34

In: arr=( $line ). La "divisione" viene associata a "glob".
I caratteri jolly ( *, ?e[] ) sarà ampliato a nomi di file corrispondenti.

La soluzione corretta è solo leggermente più complessa:

IFS=' ' read -a arr <<< "$line"

Nessun problema globbing; il carattere diviso è impostato in $IFS, variabili tra virgolette.


5
Questa dovrebbe essere la risposta accettata. La dichiarazione arr=($line)nella risposta accettata soffre di problemi preoccupanti. Ad esempio, provare: line="twinkling *"; arr=($line); declare -p arr.
codeforester

La citazione è facoltativa per il herestring, <<<ma può essere una buona idea utilizzare ancora virgolette doppie per coerenza e leggibilità.
codeforester

7

Se hai bisogno di espansione dei parametri, prova:

eval "arr=($line)"

Ad esempio, prendi il seguente codice.

line='a b "c d" "*" *'
eval "arr=($line)"
for s in "${arr[@]}"; do 
    echo "$s"
done

Se la directory corrente conteneva i file a.txt, b.txte c.txt, quindi l'esecuzione il codice produrrebbe il seguente output.

a
b
c d
*
a.txt
b.txt
c.txt

-9
line="1 1.50 string"

arr=$( $line | tr " " "\n")

for x in $arr
do
echo "> [$x]"
done

Il looping è errato, divide bene l'array e il pipe in trè superfluo, ma dovrebbe "${arr[@]}"$arr
ricircolare
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.