Veränderbare Listen- oder Arraystruktur in Bash? Wie kann ich es einfach anhängen?

69

Ich versuche, Zeichenfolgenwerte in einem Bash-Skript zu sammeln. Was ist die einfachste Möglichkeit, Zeichenfolgenwerte an eine Liste oder Array-Struktur anzuhängen, sodass ich sie am Ende wiedergeben kann?

Joe
quelle

Antworten:

118
$ arr=(1 2 3)
$ arr+=(4)
$ echo ${arr[@]}
1 2 3 4

Da Bash spärliche Arrays verwendet, sollten Sie die Elementanzahl nicht ${#arr}als Index verwenden. Sie können jedoch eine Reihe von Indizes wie folgt erhalten:

$ indices=(${!arr[@]})
Dennis Williamson
quelle
13
foo=(a b c)
foo=("${foo[@]}" d)
for i in "${foo[@]}"; do echo "$i" ; done
Ignacio Vazquez-Abrams
quelle
4

Um zu dem hinzuzufügen, was Ignacio in einer anderen Antwort vorgeschlagen hat:

foo=(a b c)
foo=("${foo[@]}" d) # push element 'd'

foo[${#foo[*]}]="e" # push element 'e'

for i in "${foo[@]}"; do echo "$i" ; done
Codaddict
quelle
4
$ for i in "string1" "string2" "string3"
> do
> array+=($i)
> done
$ echo ${array[@]}
string1 string2 string3
Ghostdog74
quelle
2

Die eher obskure Syntax zum Anhängen an das Ende eines Arrays in Bash lautet:

myarr[${#myarr[*]}]=”$newitem
ennuikiller
quelle
Wie Dennis Williamsons Antwort hervorhebt, ist dies in einigen Fällen falsch. Bash-Arrays sind spärlich und der Index $ {# myarr [*]} ist möglicherweise nicht der letzte Index.
Evan Krall
0

Obwohl die Frage beantwortet wurde und ziemlich alt ist, möchte ich eine Namespace-Lösung teilen, da sie mit Ausnahme der Antwort von Ennukiller erheblich schneller funktioniert als alle anderen Methoden (bei meinen Tests mit 100.000 Zeilen hat sie ~ 12 Sekunden gegen meine ~ 14 gewonnen Sekunden, während die Lösung zum Anhängen von Listen einige Minuten dauern würde).

Sie können den folgenden Trick verwenden:

# WORKS FASTER THAN THESE LAME LISTS! ! !
size=0;while IFS= read -r line; do
    echo $line
    ((++size))
    eval "SWAMP_$size='$line'"
done

Oder Sie können Folgendes tun:

#!/bin/bash
size=0
namespace="SWAMP"

ArrayAppend() {
    namespace="$1"
    # suppose array size is global
    new_value="$2"
    eval "${namespace}_$size='$2'"
    eval "echo \$${namespace}_$size"
    ((++size))
}

ArrayAppend "$namespace" "$RANDOM"
ArrayAppend "$namespace" "$RANDOM"
ArrayAppend "$namespace" "$RANDOM"
ArrayAppend "$namespace" "$RANDOM"
ArrayAppend "$namespace" "$RANDOM"

Solange sich der Interpreter in der Tag-Liste befindet, finden Sie hier einen Link für objektorientiertes Bash .

theoden8
quelle
Nicht evalfür die Zuweisung verwenden (insbesondere bei Benutzereingaben)! Ihr Code unterliegt der Code-Injektion und ist sehr unsicher (und daher fehlerhaft)! Also ... es ist noch lamer als lahme Listen :).
gniourf_gniourf
Übrigens, wenn Ihr einziges Ziel darin besteht, Ihre Datei Zeile für Zeile in einem Array zu schlürfen, sollten Sie mit Bash≥4 Folgendes verwenden mapfile: mapfile -t lines < file.
gniourf_gniourf
Wenn Sie fragen, kann ich Ihnen jedoch eine sehr wenig bekannte Art der evalsicheren Verwendung zeigen ...
gniourf_gniourf
@gniourf_gniourf, sicher. Das würde ich gerne sehen.
Theoden8
1
mapfileist ein eingebauter Bash (Sie befinden sich in einer Frage, die mit Bash markiert ist ).
gniourf_gniourf