Entfernen Sie ein Element aus einem Bash-Array


116

Ich muss ein Element aus einem Array in der Bash-Shell entfernen. Im Allgemeinen würde ich einfach tun:

array=("${(@)array:#<element to remove>}")

Leider ist das Element, das ich entfernen möchte, eine Variable, sodass ich den vorherigen Befehl nicht verwenden kann. Hier unten ein Beispiel:

array+=(pluto)
array+=(pippo)
delete=(pluto)
array( ${array[@]/$delete} ) -> but clearly doesn't work because of {}

Irgendeine Idee?


Welche Schale? Ihr Beispiel sieht aus wie zsh.
Chepner

array=( ${array[@]/$delete} )funktioniert wie erwartet in Bash. Hast du das einfach verpasst =?
Ken Sharp

1
@ Ken, das ist nicht ganz das, was gewünscht wird - es werden alle Übereinstimmungen aus jeder Zeichenfolge entfernt und leere Zeichenfolgen in dem Array belassen, in dem es mit der gesamten Zeichenfolge übereinstimmt.
Toby Speight

Antworten:


165

Folgendes funktioniert wie in bashund zsh:

$ array=(pluto pippo)
$ delete=pluto
$ echo ${array[@]/$delete}
pippo
$ array=( "${array[@]/$delete}" ) #Quotes when working with strings

Wenn Sie mehr als ein Element löschen müssen:

...
$ delete=(pluto pippo)
for del in ${delete[@]}
do
   array=("${array[@]/$del}") #Quotes when working with strings
done

Vorbehalt

Diese Technik entfernt tatsächlich Präfixe, die mit $deleteden Elementen übereinstimmen , nicht unbedingt ganze Elemente.

Aktualisieren

Um ein genaues Element wirklich zu entfernen, müssen Sie durch das Array gehen, das Ziel mit jedem Element vergleichen und unseteine genaue Übereinstimmung löschen.

array=(pluto pippo bob)
delete=(pippo)
for target in "${delete[@]}"; do
  for i in "${!array[@]}"; do
    if [[ ${array[i]} = $target ]]; then
      unset 'array[i]'
    fi
  done
done

Wenn Sie dies tun und ein oder mehrere Elemente entfernt werden, sind die Indizes keine fortlaufende Folge von Ganzzahlen mehr.

$ declare -p array
declare -a array=([0]="pluto" [2]="bob")

Die einfache Tatsache ist, dass Arrays nicht für die Verwendung als veränderbare Datenstrukturen konzipiert wurden. Sie werden hauptsächlich zum Speichern von Elementlisten in einer einzelnen Variablen verwendet, ohne dass ein Zeichen als Trennzeichen verschwendet werden muss (z. B. zum Speichern einer Liste von Zeichenfolgen, die Leerzeichen enthalten können).

Wenn Lücken ein Problem darstellen, müssen Sie das Array neu erstellen, um die Lücken zu füllen:

for i in "${!array[@]}"; do
    new_array+=( "${array[i]}" )
done
array=("${new_array[@]}")
unset new_array

43
nur wissen, dass: $ array=(sun sunflower) $ delete=(sun) $ echo ${array[@]/$delete}Ergebnisse inflower
Bernstein

12
Beachten Sie, dass dies tatsächlich eine Ersetzung durchführt. Wenn das Array also so etwas wie (pluto1 pluto2 pippo)ist, werden Sie am Ende mit (1 2 pippo).
Haridsv

5
Seien Sie vorsichtig, wenn Sie dies in einer for-Schleife verwenden, da Sie am Ende ein leeres Element haben, in dem sich das gelöschte Element befand. Aus Gründen der Vernunft könnten Sie so etwas tunfor element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Joel B

2
Wie lösche ich also nur passende Elemente?
UmaN

4
Hinweis: Dadurch wird der jeweilige Wert möglicherweise auf nichts gesetzt, das Element befindet sich jedoch weiterhin im Array.
Phil294

29

Sie können ein neues Array ohne das unerwünschte Element erstellen und es dann wieder dem alten Array zuweisen. Dies funktioniert in bash:

array=(pluto pippo)
new_array=()
for value in "${array[@]}"
do
    [[ $value != pluto ]] && new_array+=($value)
done
array=("${new_array[@]}")
unset new_array

Dies ergibt:

echo "${array[@]}"
pippo

14

Dies ist der direkteste Weg, um einen Wert zu deaktivieren, wenn Sie seine Position kennen.

$ array=(one two three)
$ echo ${#array[@]}
3
$ unset 'array[1]'
$ echo ${array[@]}
one three
$ echo ${#array[@]}
2

3
Versuchen Sie echo ${array[1]}, Sie erhalten eine Nullzeichenfolge. Und um threeSie zu bekommen , müssen Sie tun echo ${array[2]}. Es unsetist also nicht der richtige Mechanismus, um ein Element im Bash-Array zu entfernen.
Rashok

@rashok, nein, ${array[1]+x}ist eine Nullzeichenfolge, daher array[1]nicht gesetzt. unsetändert die Indizes der verbleibenden Elemente nicht. Das Zitieren des Arguments für nicht gesetzt ist nicht erforderlich. Die Art und Weise, ein Array-Element zu zerstören, wird im Bash-Handbuch beschrieben .
Jarno

@ Rashok Ich verstehe nicht warum nicht. Sie können nicht davon ausgehen, dass dies ${array[1]}existiert, nur weil die Größe 2 ist. Wenn Sie die Indizes möchten, überprüfen Sie ${!array[@]}.
Daniel C. Sobral

4

Hier ist eine einzeilige Lösung mit Mapfile:

$ mapfile -d $'\0' -t arr < <(printf '%s\0' "${arr[@]}" | grep -Pzv "<regexp>")

Beispiel:

$ arr=("Adam" "Bob" "Claire"$'\n'"Smith" "David" "Eve" "Fred")

$ echo "Size: ${#arr[*]} Contents: ${arr[*]}"

Size: 6 Contents: Adam Bob Claire
Smith David Eve Fred

$ mapfile -d $'\0' -t arr < <(printf '%s\0' "${arr[@]}" | grep -Pzv "^Claire\nSmith$")

$ echo "Size: ${#arr[*]} Contents: ${arr[*]}"

Size: 5 Contents: Adam Bob David Eve Fred

Diese Methode ermöglicht eine große Flexibilität durch Ändern / Austauschen des Befehls grep und hinterlässt keine leeren Zeichenfolgen im Array.


1
Bitte verwenden Sie printf '%s\n' "${array[@]}"anstelle dieses hässlichen IFS/ echoDings.
gniourf_gniourf

Beachten Sie, dass dies bei Feldern fehlschlägt, die Zeilenumbrüche enthalten.
gniourf_gniourf

@Socowi Du bist falsch, zumindest bei Bash 4.4.19. -d $'\0'funktioniert einwandfrei, nur -dohne das Argument nicht.
Niklas Holm

Ah ja, ich habe es verwechselt. Es tut uns leid. Was ich meinte war: -d $'\0'ist das gleiche wie -d $'\0 something'oder nur -d ''.
Socowi

Es tut nicht weh, es $'\0'aus Gründen der Klarheit zu verwenden
Niklas Holm

4

Diese Antwort ist spezifisch für den Fall, dass mehrere Werte aus großen Arrays gelöscht werden, bei denen die Leistung wichtig ist.

Die am häufigsten gewählten Lösungen sind (1) Mustersubstitution in einem Array oder (2) Iteration über die Array-Elemente. Das erste ist schnell, kann jedoch nur Elemente mit einem bestimmten Präfix behandeln, das zweite hat O (n * k), n = Arraygröße, k = zu entfernende Elemente. Assoziative Arrays sind relativ neue Funktionen und waren möglicherweise nicht üblich, als die Frage ursprünglich gestellt wurde.

Für den exakten Übereinstimmungsfall mit großem n und k kann die Leistung von O (n k) auf O (n + k log (k)) verbessert werden . In der Praxis nimmt O (n) an, dass k viel niedriger als n ist. Der größte Teil der Beschleunigung basiert auf der Verwendung eines assoziativen Arrays zur Identifizierung der zu entfernenden Elemente.

Leistung (n-Array-Größe, zu löschende k-Werte). Die Leistung misst Sekunden der Benutzerzeit

   N     K     New(seconds) Current(seconds)  Speedup
 1000   10     0.005        0.033             6X
10000   10     0.070        0.348             5X
10000   20     0.070        0.656             9X
10000    1     0.043        0.050             -7%

Wie erwartet ist die currentLösung linear zu N * K und die fastLösung ist praktisch linear zu K mit einer viel niedrigeren Konstante. Die fastLösung ist currentaufgrund des zusätzlichen Aufbaus etwas langsamer als die Lösung, wenn k = 1 ist.

Die 'schnelle' Lösung: Array = Liste der Eingaben, Löschen = Liste der zu entfernenden Werte.

        declare -A delk
        for del in "${delete[@]}" ; do delk[$del]=1 ; done
                # Tag items to remove, based on
        for k in "${!array[@]}" ; do
                [ "${delk[${array[$k]}]-}" ] && unset 'array[k]'
        done
                # Compaction
        array=("${array[@]}")

Vergleich mit der currentLösung anhand der am häufigsten gewählten Antwort.

    for target in "${delete[@]}"; do
        for i in "${!array[@]}"; do
            if [[ ${array[i]} = $target ]]; then
                unset 'array[i]'
            fi
        done
    done
    array=("${array[@]}")

3

Hier ist eine (wahrscheinlich sehr bash-spezifische) kleine Funktion, die die Indirektion von Bash-Variablen beinhaltet und unset; Es handelt sich um eine allgemeine Lösung, bei der kein Text ersetzt oder leere Elemente verworfen werden und keine Probleme mit Anführungszeichen / Leerzeichen usw. auftreten.

delete_ary_elmt() {
  local word=$1      # the element to search for & delete
  local aryref="$2[@]" # a necessary step since '${!$2[@]}' is a syntax error
  local arycopy=("${!aryref}") # create a copy of the input array
  local status=1
  for (( i = ${#arycopy[@]} - 1; i >= 0; i-- )); do # iterate over indices backwards
    elmt=${arycopy[$i]}
    [[ $elmt == $word ]] && unset "$2[$i]" && status=0 # unset matching elmts in orig. ary
  done
  return $status # return 0 if something was deleted; 1 if not
}

array=(a 0 0 b 0 0 0 c 0 d e 0 0 0)
delete_ary_elmt 0 array
for e in "${array[@]}"; do
  echo "$e"
done

# prints "a" "b" "c" "d" in lines

Verwenden Sie es wie delete_ary_elmt ELEMENT ARRAYNAMEohne $Siegel. Schalten Sie das == $wordfür == $word*für Präfix-Übereinstimmungen; Verwendung ${elmt,,} == ${word,,}für Übereinstimmungen ohne Berücksichtigung der Groß- und Kleinschreibung; usw., was auch immer Bash [[unterstützt.

Dabei werden die Indizes des Eingabearrays ermittelt und rückwärts durchlaufen (das Löschen von Elementen führt also nicht zu einer Verschiebung der Iterationsreihenfolge). Um die Indizes zu erhalten, müssen Sie nach Namen auf das Eingabearray zugreifen. Dies kann über die Indirektion von Bash-Variablen erfolgen x=1; varname=x; echo ${!varname} # prints "1".

Sie können nicht namentlich auf Arrays zugreifen aryname=a; echo "${$aryname[@]}, dies gibt Ihnen einen Fehler. Sie können nicht tun aryname=a; echo "${!aryname[@]}", dies gibt Ihnen die Indizes der Variablenaryname (obwohl es sich nicht um ein Array handelt). Was funktioniert, ist aryref="a[@]"; echo "${!aryref}", dass die Elemente des Arrays gedruckt werden a, wobei Shell-Word-Anführungszeichen und Leerzeichen genau wie erhalten bleiben echo "${a[@]}". Dies funktioniert jedoch nur zum Drucken der Elemente eines Arrays, nicht zum Drucken seiner Länge oder Indizes ( aryref="!a[@]"oder aryref="#a[@]"oder "${!!aryref}"oder"${#!aryref}" , alle schlagen fehl).

Also kopiere ich das ursprüngliche Array durch seinen Namen per Bash-Indirektion und erhalte die Indizes aus der Kopie. Um die Indizes in umgekehrter Reihenfolge zu durchlaufen, verwende ich eine for-Schleife im C-Stil. Ich könnte es auch tun, indem ich über auf die Indizes zugreife ${!arycopy[@]}und sie umkehre tac, was eine Umkehrung catder Eingabezeilenreihenfolge ist.

Eine Funktionslösung ohne variable Indirektion müsste wahrscheinlich beinhalten eval, was in dieser Situation sicher sein kann oder nicht (ich kann es nicht sagen).


Dies funktioniert fast einwandfrei, deklariert jedoch das an die Funktion übergebene anfängliche Array nicht neu. Während bei diesem anfänglichen Array die Werte fehlen, sind auch die Indizes durcheinander. Dies bedeutet, dass der nächste Aufruf von delete_ary_elmt auf demselben Array nicht funktioniert (oder die falschen Dinge entfernt). Versuchen Sie beispielsweise nach dem Einfügen, delete_ary_elmt "d" arraydas Array auszuführen und anschließend erneut zu drucken. Sie werden sehen, dass das falsche Element entfernt wird. Das Entfernen des letzten Elements funktioniert dann auch nie.
Scott

2

Um die obigen Antworten zu erweitern, können Sie die folgenden Elemente verwenden, um mehrere Elemente ohne teilweise Übereinstimmung aus einem Array zu entfernen:

ARRAY=(one two onetwo three four threefour "one six")
TO_REMOVE=(one four)

TEMP_ARRAY=()
for pkg in "${ARRAY[@]}"; do
    for remove in "${TO_REMOVE[@]}"; do
        KEEP=true
        if [[ ${pkg} == ${remove} ]]; then
            KEEP=false
            break
        fi
    done
    if ${KEEP}; then
        TEMP_ARRAY+=(${pkg})
    fi
done
ARRAY=("${TEMP_ARRAY[@]}")
unset TEMP_ARRAY

Dies führt zu einem Array, das Folgendes enthält: (zwei, zwei, drei, drei, vier "eins, sechs")



1

Nur teilweise Antwort

So löschen Sie das erste Element im Array

unset 'array[0]'

So löschen Sie das letzte Element im Array

unset 'array[-1]'

@gniourf_gniourf Es ist nicht erforderlich, Anführungszeichen für das Argument von zu verwenden unset.
Jarno

2
@jarno: Diese Anführungszeichen MÜSSEN verwendet werden: Wenn Sie eine Datei mit dem Namen array0im aktuellen Verzeichnis haben, wird diese, da sie array[0]glob ist, zuerst array0vor dem Befehl unset erweitert.
gniourf_gniourf

@gniourf_gniourf du bist richtig. Dies sollte im Bash-Referenzhandbuch korrigiert werden , das derzeit besagt, dass "nicht festgelegter Name [Index] das Array-Element am Index-Index zerstört".
Jarno

1

Verwenden von unset

Um ein Element an einem bestimmten Index zu entfernen, können wir es verwenden unsetund dann in ein anderes Array kopieren. Nur gerade unsetist in diesem Fall nicht erforderlich. Da unsetdas Element nicht entfernt wird, wird lediglich eine Nullzeichenfolge für den bestimmten Index im Array festgelegt.

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
unset 'arr[1]'
declare -a arr2=()
i=0
for element in "${arr[@]}"
do
    arr2[$i]=$element
    ((++i))
done
echo "${arr[@]}"
echo "1st val is ${arr[1]}, 2nd val is ${arr[2]}"
echo "${arr2[@]}"
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

Ausgabe ist

aa cc dd ee
1st val is , 2nd val is cc
aa cc dd ee
1st val is cc, 2nd val is dd

Verwenden von :<idx>

Wir können einige Elemente auch mit entfernen :<idx>. Wenn wir zum Beispiel das erste Element entfernen möchten, können wir es :1wie unten erwähnt verwenden.

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
arr2=("${arr[@]:1}")
echo "${arr2[@]}"
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

Ausgabe ist

bb cc dd ee
1st val is cc, 2nd val is dd

0

Das POSIX-Shell-Skript verfügt nicht über Arrays.

Sie verwenden also höchstwahrscheinlich einen bestimmten Dialekt wie bashKornschalen oder zsh.

Daher kann Ihre Frage derzeit nicht beantwortet werden.

Vielleicht funktioniert das für Sie:

unset array[$delete]

2
Hallo, ich benutze Bash Shell atm. Und "$ delete" ist nicht die Position des Elements, sondern die Zeichenfolge selbst. Also ich denke nicht, dass "unset" funktionieren wird
Alex

0

Eigentlich ist mir gerade aufgefallen, dass in der Shell-Syntax ein Verhalten eingebaut ist, das eine einfache Rekonstruktion des Arrays ermöglicht, wenn, wie in der Frage gestellt, ein Element entfernt werden sollte.

# let's set up an array of items to consume:
x=()
for (( i=0; i<10; i++ )); do
    x+=("$i")
done

# here, we consume that array:
while (( ${#x[@]} )); do
    i=$(( $RANDOM % ${#x[@]} ))
    echo "${x[i]} / ${x[@]}"
    x=("${x[@]:0:i}" "${x[@]:i+1}")
done

Beachten Sie, wie wir das Array mit der Bash- x+=()Syntax erstellt haben?

Sie können damit tatsächlich mehr als ein Element hinzufügen, den Inhalt eines ganzen anderen Arrays gleichzeitig.


0

http://wiki.bash-hackers.org/syntax/pe#substring_removal

$ {PARAMETER # PATTERN} # vom Anfang entfernen

$ {PARAMETER ## PATTERN} # von Anfang an entfernen, gieriges Match

$ {PARAMETER% PATTERN} # vom Ende entfernen

$ {PARAMETER %% PATTERN} # am Ende entfernen, gieriges Match

Um ein vollständig entferntes Element auszuführen, müssen Sie einen nicht gesetzten Befehl mit einer if-Anweisung ausführen. Wenn Sie keine Präfixe aus anderen Variablen entfernen oder Leerzeichen im Array unterstützen möchten, können Sie einfach die Anführungszeichen löschen und for-Schleifen vergessen.

Im folgenden Beispiel finden Sie einige verschiedene Möglichkeiten zum Bereinigen eines Arrays.

options=("foo" "bar" "foo" "foobar" "foo bar" "bars" "bar")

# remove bar from the start of each element
options=("${options[@]/#"bar"}")
# options=("foo" "" "foo" "foobar" "foo bar" "s" "")

# remove the complete string "foo" in a for loop
count=${#options[@]}
for ((i = 0; i < count; i++)); do
   if [ "${options[i]}" = "foo" ] ; then
      unset 'options[i]'
   fi
done
# options=(  ""   "foobar" "foo bar" "s" "")

# remove empty options
# note the count variable can't be recalculated easily on a sparse array
for ((i = 0; i < count; i++)); do
   # echo "Element $i: '${options[i]}'"
   if [ -z "${options[i]}" ] ; then
      unset 'options[i]'
   fi
done
# options=("foobar" "foo bar" "s")

# list them with select
echo "Choose an option:"
PS3='Option? '
select i in "${options[@]}" Quit
 do
    case $i in 
       Quit) break ;;
       *) echo "You selected \"$i\"" ;;
    esac
 done

Ausgabe

Choose an option:
1) foobar
2) foo bar
3) s
4) Quit
Option? 

Hoffentlich hilft das.


0

In ZSH ist dies kinderleicht (beachten Sie, dass zum besseren Verständnis mehr bash-kompatible Syntax als erforderlich verwendet wird):

# I always include an edge case to make sure each element
# is not being word split.
start=(one two three 'four 4' five)
work=(${(@)start})

idx=2
val=${work[idx]}

# How to remove a single element easily.
# Also works for associative arrays (at least in zsh)
work[$idx]=()

echo "Array size went down by one: "
[[ $#work -eq $(($#start - 1)) ]] && echo "OK"

echo "Array item "$val" is now gone: "
[[ -z ${work[(r)$val]} ]] && echo OK

echo "Array contents are as expected: "
wanted=("${start[@]:0:1}" "${start[@]:2}")
[[ "${(j.:.)wanted[@]}" == "${(j.:.)work[@]}" ]] && echo "OK"

echo "-- array contents: start --"
print -l -r -- "-- $#start elements" ${(@)start}
echo "-- array contents: work --"
print -l -r -- "-- $#work elements" "${work[@]}"

Ergebnisse:

Array size went down by one:
OK
Array item two is now gone:
OK
Array contents are as expected:
OK
-- array contents: start --
-- 5 elements
one
two
three
four 4
five
-- array contents: work --
-- 4 elements
one
three
four 4
five

Entschuldigung, habe es gerade versucht. Es funktionierte nicht in zsh für ein assoziatives Array
Falk

Es funktioniert gut, ich habe es gerade (wieder) getestet. Dinge, die bei Ihnen nicht funktionieren? Bitte erläutern Sie so genau wie möglich, was nicht genau funktioniert hat. Welche ZSH-Version verwenden Sie?
Trevorj

0

Es gibt auch diese Syntax, z. B. wenn Sie das 2. Element löschen möchten:

array=("${array[@]:0:1}" "${array[@]:2}")

Das ist in der Tat die Verkettung von 2 Registerkarten. Der erste vom Index 0 bis zum Index 1 (exklusiv) und der zweite vom Index 2 bis zum Ende.


-1

Was ich tue ist:

array="$(echo $array | tr ' ' '\n' | sed "/itemtodelete/d")"

BAM, dieser Gegenstand wird entfernt.


1
Das bricht für array=('first item' 'second item').
Benjamin W.

-1

Dies ist eine schnelle und schmutzige Lösung, die in einfachen Fällen funktioniert, aber nicht funktioniert, wenn (a) Regex-Sonderzeichen enthalten $deletesind oder (b) in Elementen überhaupt Leerzeichen vorhanden sind. Beginnen mit:

array+=(pluto)
array+=(pippo)
delete=(pluto)

Löschen Sie alle Einträge, die genau übereinstimmen $delete:

array=(`echo $array | fmt -1 | grep -v "^${delete}$" | fmt -999999`)

in resultierenden echo $array-> Pippo, und sicherstellen , dass es ein Array: echo $array[1]-> Pippo

fmtist ein wenig dunkel: fmt -1Zeilenumbrüche in der ersten Spalte (um jedes Element in eine eigene Zeile zu setzen. Hier tritt das Problem bei Elementen in Leerzeichen auf.) fmt -999999wickeln es in eine Zeile zurück und setzen die Leerzeichen zwischen den Elementen zurück. Es gibt andere Möglichkeiten, dies zu tun, wie z xargs.

Nachtrag: Wenn Sie nur die erste Übereinstimmung löschen möchten, verwenden Sie sed wie hier beschrieben :

array=(`echo $array | fmt -1 | sed "0,/^${delete}$/{//d;}" | fmt -999999`)

-1

Wie wäre es mit so etwas wie:

array=(one two three)
array_t=" ${array[@]} "
delete=one
array=(${array_t// $delete / })
unset array_t

-1

Um Konflikte mit dem Array-Index zu vermeiden, indem Sie unset- siehe https://stackoverflow.com/a/49626928/3223785 und https://stackoverflow.com/a/47798640/3223785 für weitere Informationen - das Array sich selbst neu zuweisen : ARRAY_VAR=(${ARRAY_VAR[@]}).

#!/bin/bash

ARRAY_VAR=(0 1 2 3 4 5 6 7 8 9)
unset ARRAY_VAR[5]
unset ARRAY_VAR[4]
ARRAY_VAR=(${ARRAY_VAR[@]})
echo ${ARRAY_VAR[@]}
A_LENGTH=${#ARRAY_VAR[*]}
for (( i=0; i<=$(( $A_LENGTH -1 )); i++ )) ; do
    echo ""
    echo "INDEX - $i"
    echo "VALUE - ${ARRAY_VAR[$i]}"
done

exit 0

[Ref.: Https://tecadmin.net/working-with-array-bash-script/ ]


-2
#/bin/bash

echo "# define array with six elements"
arr=(zero one two three 'four 4' five)

echo "# unset by index: 0"
unset -v 'arr[0]'
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

arr_delete_by_content() { # value to delete
        for i in ${!arr[*]}; do
                [ "${arr[$i]}" = "$1" ] && unset -v 'arr[$i]'
        done
        }

echo "# unset in global variable where value: three"
arr_delete_by_content three
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

echo "# rearrange indices"
arr=( "${arr[@]}" )
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

delete_value() { # value arrayelements..., returns array decl.
        local e val=$1; new=(); shift
        for e in "${@}"; do [ "$val" != "$e" ] && new+=("$e"); done
        declare -p new|sed 's,^[^=]*=,,'
        }

echo "# new array without value: two"
declare -a arr="$(delete_value two "${arr[@]}")"
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

delete_values() { # arraydecl values..., returns array decl. (keeps indices)
        declare -a arr="$1"; local i v; shift
        for v in "${@}"; do 
                for i in ${!arr[*]}; do
                        [ "$v" = "${arr[$i]}" ] && unset -v 'arr[$i]'
                done
        done
        declare -p arr|sed 's,^[^=]*=,,'
        }
echo "# new array without values: one five (keep indices)"
declare -a arr="$(delete_values "$(declare -p arr|sed 's,^[^=]*=,,')" one five)"
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

# new array without multiple values and rearranged indices is left to the reader

1
Können Sie einige Kommentare oder eine Beschreibung hinzufügen, um uns Ihre Antwort mitzuteilen?
Michael
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.