Lesen einer durch Trennzeichen getrennten Zeichenfolge in ein Array in Bash

206

Ich habe eine Variable, die eine durch Leerzeichen getrennte Zeichenfolge enthält:

line="1 1.50 string"

Ich möchte diese Zeichenfolge mit Leerzeichen als Trennzeichen teilen und das Ergebnis in einem Array speichern, so dass Folgendes:

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

Ausgänge

1
1.50
string

Irgendwo habe ich eine Lösung gefunden, die nicht funktioniert:

arr=$(echo ${line})

Wenn ich danach die obigen Echoanweisungen ausführe, erhalte ich:

1 1.50 string
[empty line]
[empty line]

Ich habe es auch versucht

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

mit dem gleichen Ergebnis. Kann mir bitte jemand helfen?

Nikola Novak
quelle
Siehe diese Antwort unter Unix & Linux Stack Exchange: Verwenden von sed with herestring (<<<) und lesen Sie -a . set -f; arr=($string); set +fscheint schneller zu sein als read -r -a <<< $string.
Codeforester

Antworten:

331

Um einen String in ein Array zu konvertieren, verwenden Sie bitte

arr=($line)

oder

read -a arr <<< $line

Es ist wichtig, keine Anführungszeichen zu verwenden, da dies den Trick macht.

kev
quelle
7
und um eine Überprüfung der for i in ${arr[@]}; do echo $i; done
Gesundheit
5
oder einfachecho ${arr[@]}
Banjer
13
Beide Möglichkeiten können fehlschlagen, wenn $lineGlobbing-Zeichen enthalten sind. mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}gibt 3
Tino
3
declare -a "arr=($line)"wird IFSTrennzeichen in Anführungszeichen ignorieren
Dave
4
@Tino Nr Wenn line='*', read -a arr <<<$lineimmer, aber nur arr=($line)versagt.
Johnny Wong
39

Versuche dies:

arr=(`echo ${line}`);
Geil
quelle
5
Nizza - Diese Lösung funktioniert auch in der Z-Shell, wo einige der anderen oben genannten Ansätze fehlschlagen.
Keith Hughitt
Es macht die Arbeit, können Sie bitte erklären, warum es funktioniert?
Smartwjw
2
Bemerkung: Dies funktioniert auch nicht, wenn die Zeile '*' enthält, wieline='*'
Johnny Wong
34

In : arr=( $line ). Die "Aufteilung" ist mit "glob" verbunden.
Platzhalter ( *, ?und []) werden auf übereinstimmende Dateinamen erweitert.

Die richtige Lösung ist nur geringfügig komplexer:

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

Kein Globbing-Problem; Das geteilte Zeichen wird in $IFSVariablen gesetzt.

Isaac
quelle
5
Dies sollte die akzeptierte Antwort sein. Die Aussage arr=($line)in der akzeptierten Antwort leidet unter globalen Problemen. Versuchen Sie zum Beispiel : line="twinkling *"; arr=($line); declare -p arr.
Codeforester
Anführungszeichen sind für Herestring optional, <<<es kann jedoch eine gute Idee sein, aus Gründen der Konsistenz und Lesbarkeit weiterhin doppelte Anführungszeichen zu verwenden.
Codeforester
6

Wenn Sie eine Parametererweiterung benötigen, versuchen Sie Folgendes:

eval "arr=($line)"

Nehmen Sie zum Beispiel den folgenden Code.

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

Wenn das aktuelle Verzeichnis enthaltenen Dateien a.txt, b.txtund c.txtdann die Ausführung von Code würde die folgende Ausgabe erzeugen.

a
b
c d
*
a.txt
b.txt
c.txt
David Anderson
quelle
-9
line="1 1.50 string"

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

for x in $arr
do
echo "> [$x]"
done
Hitesh
quelle
Die Schleife ist falsch, es teilt das Array fein auf und die Pipe trist überflüssig, aber es sollte "${arr[@]}"stattdessen eine Schleife $arr
durchlaufen