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?


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.


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}`);

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.


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

-9
line="1 1.50 string"

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

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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.