So deaktivieren Sie den Arraybereich in Bash

8

Ich versuche, den Bereich des Array-Elements zu löschen, aber es ist fehlgeschlagen.

Mein Array

root@ubuntu:~/work# echo ${a[@]}
cocacola.com airtel.com pepsi.com

Das 0-1-Array drucken sieht in Ordnung aus

root@ubuntu:~/work# echo ${a[@]::2}
cocacola.com airtel.com

Jetzt versuche ich nur diese Elemente zu löschen mit:

root@ubuntu:~/work# unset a[@]::2
root@ubuntu:~/work# echo ${a[@]}

Es löscht das ganze Array.

Was mache ich falsch?

Ich habe eine andere Möglichkeit gefunden, einen Array-Bereich zu löschen, aber warum funktionieren die oben genannten Dinge nicht?

for ((i=0; i<2; i++)); do unset a[$i]; done

EDIT hatte ich auch versucht aber kein Glück

unset -v 'a[@]::2'
Rahul Patil
quelle

Antworten:

14

Eine Sache, die zu beachten ist, ist, dass bashimplementierte Arrays wie kshassoziative Arrays, bei denen Schlüssel auf positive ganze Zahlen beschränkt sind (im Gegensatz zu anderen Sprachen wie perloder zshzum Beispiel).

Im:

a[123]=foo a[456]=bar a[789]=baz

In bash haben Sie ein assoziatives Array mit 3 Elementen, während Sie in bash perlein Array mit 790 Elementen haben (789 mit zsh).

In kshoder bash, ${a[@]:0:1}gibt das erste Element des Feldes in der Liste von Elementen sortierte numerisch durch Schlüssel , wo der Schlüssel ist größer oder gleich 0 , so dass in diesem Fall, gibt sie ${a[123]}nicht ${a[0]}.

unset 'a[123]'

(Denken Sie daran, es zu zitieren, da es sonst fehlschlagen würde, wenn sich im aktuellen Verzeichnis eine Datei mit den Namen a1 oder a2 oder a3 befindet.) Dies ist sinnvoll, da ein bestimmter Schlüssel im Array entfernt wird.

unset 'a[@]::2'

macht aber weniger Sinn. bashnur versteht unset a, unset 'a[123]'oder unset 'a[*/@]', etwas nach ignoriert wird, so unset 'a[@]::2'und unset 'a[@]please'das gleiche tun: unset das gesamte Array.

Wenn Sie einen Tastenbereich deaktivieren möchten, müssen Sie die Tasten durchlaufen:

Um die Liste der Schlüssel des Arrays zu erhalten, lautet die Syntax "${!a[@]}". Leider funktioniert das Anwenden eines Bereichs nicht mit bashnoch ksh, sodass Sie ein temporäres Array benötigen:

keys=("${!a[@]}")
for i in "${keys[@]::2}"; do unset "a[$i]"; done

Wenn Sie diese Arrays nun wie in anderen Sprachen betrachten möchten, möchten Sie sie nicht verwenden unset. Wenn das Array an erster Stelle nicht dünn ist und Sie es beibehalten möchten (dh alle Elemente um 2 verschieben, anstatt die ersten beiden zu deaktivieren), können Sie Folgendes tun:

a=("${a[@]:2}")

Das heißt, Sie ordnen das Array mit der Liste der Elemente neu zu, die Sie behalten möchten.

Zum Vergleich mit zsh.

a=({1..20})
unset 'a[12,16]'

würde einen leeren Wert auf die Elemente 12 bis 16 setzen, während unset 'a[16,20]'das Array auf 15 Elemente verkleinert würde.

a=({1..20})
a[12,16]=()

(noch mit zsh) würde die Elemente 17 bis 20 um 5 Positionen verschieben, also a[12]enthalten 17.

Stéphane Chazelas
quelle
Danke .. du bist mein Meister ... mit Hilfe davon habe ich ein Problem gelöst .. also schau dir das bitte an und lass mich, wenn sich dieser Bash Code verbessert
Rahul Patil
1
  1. Wenn Ihr Array kontinuierlich / nicht dünn ist (alle Elemente von 0..N-1 gesetzt)

    Sie können das 2. Element des Arrays mit entfernen

    unset 'a[1]'

    Um das 2., 3. und 4. Element zu entfernen, können Sie z

    for ((i=1; i<=3; i++)); do unset "a[$i]"; done

    Um alle Elemente außer dem 1. und 2. Element zu löschen, können Sie z

    for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
  2. Allgemeine Lösung (funktioniert auch für dünn besetzte Arrays): Sie können das 2. Element des Arrays mit entfernen

    unset "a[$(echo ${!a[@]} | cut -d" " -f 2)]"

    Um das 2., 3. und 4. Element zu entfernen, können Sie z

    for $(echo ${!a[@]} | cut -d" " -f 2-4) ; do unset "a[$i]"; done

    Um alle Elemente außer dem 1. und 2. Element zu löschen, können Sie z

    for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done
Jofel
quelle
Ich habe dies bereits getan n hatte in Frage aktualisiert .. aber Frage bleiben überunset a[@]::2
Rahul Patil
Dies ist im allgemeinen Fall falsch, da ${#a[@]}die Anzahl der Elemente im Array nicht der größte Index im Array ist ( bashArrays sind wie kshArrays im Gegensatz zu zsh spärlich).
Stéphane Chazelas
@StephaneChazelas nach dem Löschen des Elements Warum nicht den Index zurücksetzen?
Rahul Patil
@StephaneChazelas nach einigen RnD Ich habe diesen Weg gefunden, um das Array zurückzusetzen. Ist a=( $(echo ${a[@]}) ) das in Ordnung?
Rahul Patil
2
@RahulPatil, wenn Sie das Array entsparen möchten , schreiben Sie es einfach: Die a=("${a[@]}")Verwendung echound Befehlsersetzung funktioniert nur in begrenzten Eckfällen (z. B. wenn keines der Elemente leer ist oder spc, tab, NL, backslash, *,?, Enthält [oder beginnen mit -).
Stéphane Chazelas