Usuń element z tablicy Bash

116

Muszę usunąć element z tablicy w powłoce bash. Generalnie po prostu zrobiłbym:

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

Niestety element, który chcę usunąć, jest zmienną, więc nie mogę użyć poprzedniego polecenia. Oto przykład:

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

Dowolny pomysł?

Alex
źródło
Która muszla? Twój przykład wygląda jak zsh.
chepner
array=( ${array[@]/$delete} )działa zgodnie z oczekiwaniami w Bash. Czy po prostu przegapiłeś =?
Ken Sharp
1
@Ken, to nie do końca jest to, czego oczekiwaliśmy - usunie wszystkie dopasowania z każdego ciągu i pozostawi puste ciągi w tablicy, w których pasuje do całego ciągu.
Toby Speight

Odpowiedzi:

165

Następujące działa tak, jak chcesz w bashi zsh:

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

Jeśli chcesz usunąć więcej niż jeden element:

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

Caveat

Ta technika w rzeczywistości usuwa przedrostki pasujące $deletedo elementów, niekoniecznie całe elementy.

Aktualizacja

Aby naprawdę usunąć dokładny element, musisz przejść przez tablicę, porównać cel z każdym elementem i użyć unsetdo usunięcia dokładnego dopasowania.

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

Zauważ, że jeśli to zrobisz i jeden lub więcej elementów zostanie usuniętych, indeksy nie będą już ciągłą sekwencją liczb całkowitych.

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

Prosty fakt jest taki, że tablice nie zostały zaprojektowane do użytku jako zmienne struktury danych. Są używane głównie do przechowywania list elementów w pojedynczej zmiennej bez konieczności marnowania znaku jako separatora (np. Do przechowywania listy ciągów, które mogą zawierać spacje).

Jeśli luki stanowią problem, musisz przebudować tablicę, aby wypełnić luki:

for i in "${!array[@]}"; do
    new_array+=( "${array[i]}" )
done
array=("${new_array[@]}")
unset new_array
Chepner
źródło
43
po prostu wiedz, że: $ array=(sun sunflower) $ delete=(sun) $ echo ${array[@]/$delete}wyniki wflower
bernstein
12
Zauważ, że w rzeczywistości jest to podstawianie, więc jeśli tablica jest podobna (pluto1 pluto2 pippo), to skończysz z (1 2 pippo).
haridsv
5
Po prostu uważaj, używając tego w pętli for, ponieważ skończysz z pustym elementem tam, gdzie był usunięty element. Dla zdrowia psychicznego możesz zrobić coś takiegofor element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Joel B
2
Jak więc usunąć tylko pasujące elementy?
UmaN
4
Uwaga: może to ustawić odpowiednią wartość na zero, ale element nadal będzie znajdował się w tablicy.
phil294
29

Możesz utworzyć nową tablicę bez niepożądanego elementu, a następnie przypisać ją z powrotem do starej tablicy. Działa to w bash:

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

To daje:

echo "${array[@]}"
pippo
Steve Kehlet
źródło
14

Jest to najbardziej bezpośredni sposób usunięcia wartości, jeśli znasz jej pozycję.

$ array=(one two three)
$ echo ${#array[@]}
3
$ unset 'array[1]'
$ echo ${array[@]}
one three
$ echo ${#array[@]}
2
Signull
źródło
3
Spróbuj echo ${array[1]}, otrzymasz pusty ciąg. A żeby dostać three, musisz zrobić echo ${array[2]}. Nie unsetjest to więc właściwy mechanizm usuwania elementu z tablicy bash.
rashok
@rashok, no, ${array[1]+x}jest ciągiem zerowym, więc nie array[1]jest ustawione. unsetnie zmienia indeksów pozostałych elementów. Podawanie argumentu za nieustawionym nie jest potrzebne. Sposób niszczenia elementu tablicy jest opisany w podręczniku Bash .
jarno
@rashok Nie rozumiem, dlaczego nie. Nie możesz zakładać, że ${array[1]}istnieje tylko dlatego, że rozmiar wynosi 2. Jeśli chcesz indeksów, sprawdź ${!array[@]}.
Daniel C. Sobral
4

Oto rozwiązanie jednowierszowe z plikiem mapy:

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

Przykład:

$ 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

Ta metoda pozwala na dużą elastyczność poprzez modyfikację / wymianę polecenia grep i nie pozostawia żadnych pustych ciągów w tablicy.

Niklas Holm
źródło
1
Użyj printf '%s\n' "${array[@]}"zamiast tego brzydkiego IFS/ echorzeczy.
gniourf_gniourf
Zauważ, że nie powiedzie się to w przypadku pól zawierających znaki nowej linii.
gniourf_gniourf
@Socowi Mylisz się, przynajmniej na bash 4.4.19. -d $'\0'działa doskonale, podczas gdy samo -dbez argumentu nie.
Niklas Holm
Ach tak, pomieszałem to. Przepraszam. Chodziło mi o -d $'\0'to, że jest taki sam -d $'\0 something'lub sprawiedliwy -d ''.
Socowi
Nie zaszkodzi jednak użyć $'\0'dla jasności
Niklas Holm
4

Ta odpowiedź jest specyficzna dla przypadku usuwania wielu wartości z dużych tablic, w których ważna jest wydajność.

Najczęściej głosowanymi rozwiązaniami są (1) podstawianie wzorców w tablicy lub (2) iterowanie po elementach tablicy. Pierwsza jest szybka, ale może obsługiwać tylko elementy, które mają odrębny prefiks, druga ma O (n * k), n = rozmiar tablicy, k = elementy do usunięcia. Tablica asocjacyjna jest stosunkowo nową funkcją i mogła nie być powszechna, gdy pytanie zostało pierwotnie opublikowane.

Dla przypadku dokładnego dopasowania, z dużymi n i k, możliwe jest zwiększenie wydajności od O (n k) do O (n + k log (k)). W praktyce O (n) zakładając, że k jest znacznie mniejsze niż n. Większość przyspieszenia opiera się na wykorzystaniu tablicy asocjacyjnej do identyfikacji elementów do usunięcia.

Wydajność (rozmiar n-tablicy, wartości k do usunięcia). Wydajność mierzy sekundy czasu użytkownika

   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%

Zgodnie z oczekiwaniami, currentrozwiązanie jest liniowe do N * K, a fastrozwiązanie jest praktycznie liniowe do K, ze znacznie niższą stałą. fastRozwiązanie jest nieco wolniejsza vs currentroztworu gdy k = 1, ze względu na dodatkową konfigurację.

Rozwiązanie „Szybkie”: tablica = lista danych wejściowych, usuń = lista wartości do usunięcia.

        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[@]}")

Porównanie z currentrozwiązaniem, na podstawie najczęściej głosowanej odpowiedzi.

    for target in "${delete[@]}"; do
        for i in "${!array[@]}"; do
            if [[ ${array[i]} = $target ]]; then
                unset 'array[i]'
            fi
        done
    done
    array=("${array[@]}")
dash-o
źródło
3

Oto (prawdopodobnie bardzo specyficzna dla basha) mała funkcja obejmująca pośrednią zmienną basha i unset; jest to ogólne rozwiązanie, które nie obejmuje podstawiania tekstu ani odrzucania pustych elementów i nie ma problemów z cytowaniem / białymi spacjami itp.

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

Użyj go jak delete_ary_elmt ELEMENT ARRAYNAMEbez $pieczęci. Przełącz == $wordfor == $word*dla dopasowań przedrostków; użyj ${elmt,,} == ${word,,}do dopasowań bez rozróżniania wielkości liter; itp., cokolwiek [[obsługuje bash .

Działa poprzez określenie indeksów tablicy wejściowej i iterację po nich wstecz (więc usuwanie elementów nie zaburza kolejności iteracji). Aby uzyskać indeksy, musisz uzyskać dostęp do tablicy wejściowej według nazwy, co można zrobić za pośrednictwem pośredniej zmiennej bash x=1; varname=x; echo ${!varname} # prints "1".

Nie możesz uzyskać dostępu do tablic według nazwy, na przykład aryname=a; echo "${$aryname[@]}powoduje to błąd. Nie możesz tego zrobić aryname=a; echo "${!aryname[@]}", to daje indeksy zmiennej aryname(chociaż nie jest to tablica). To aryref="a[@]"; echo "${!aryref}", co działa , to wypisanie elementów tablicy a, z zachowaniem cytowania słów powłoki i białych znaków dokładnie tak, jak echo "${a[@]}". Ale to działa tylko przy drukowaniu elementów tablicy, a nie przy drukowaniu jej długości lub indeksów ( aryref="!a[@]"lub aryref="#a[@]"albo "${!!aryref}"albo "${#!aryref}", wszystkie zawodzą).

Więc kopiuję oryginalną tablicę według jej nazwy przez pośredni bash i pobieram indeksy z kopii. Aby iterować indeksy w odwrotnej kolejności, używam pętli for w stylu C. Mógłbym to również zrobić, uzyskując dostęp do indeksów za pomocą ${!arycopy[@]}i odwracając je za pomocą tac, co powoduje catzmianę kolejności linii wejściowych.

Rozwiązanie funkcyjne bez zmiennej pośredniej prawdopodobnie musiałoby obejmować eval, co może, ale nie musi, być bezpieczne w tej sytuacji (nie mogę powiedzieć).

SVP
źródło
Działa to prawie dobrze, ale nie zmienia deklaracji początkowej tablicy przekazanej do funkcji, więc chociaż w tej początkowej tablicy brakuje wartości, jej indeksy również są pomieszane. Oznacza to, że następne wywołanie delete_ary_elmt na tej samej tablicy nie zadziała (lub usunie niewłaściwe rzeczy). Na przykład po wklejeniu spróbuj uruchomić, delete_ary_elmt "d" arraya następnie ponownie wydrukować tablicę. Zobaczysz, że zły element zostanie usunięty. Usunięcie ostatniego elementu również wtedy nigdy nie zadziała.
Scott
2

Aby rozwinąć powyższe odpowiedzi, można użyć następujących poleceń do usunięcia wielu elementów z tablicy bez częściowego dopasowania:

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

Spowoduje to powstanie tablicy zawierającej: (dwa jeden dwa trzy trzy cztery „jeden sześć”)

Dylan
źródło
2

Jeśli ktoś znajdzie się w sytuacji, w której musi zapamiętać wartości set -e lub set -x i móc je przywrócić, zapoznaj się z tym streszczeniem, które używa pierwszego rozwiązania do usuwania tablicy do zarządzania własnym stosem:

https://gist.github.com/kigster/94799325e39d2a227ef89676eed44cc6

Konstantin Gredeskoul
źródło
1

Tylko częściowa odpowiedź

Aby usunąć pierwszy element z tablicy

unset 'array[0]'

Aby usunąć ostatni element z tablicy

unset 'array[-1]'
consideRatio
źródło
@gniourf_gniourf nie ma potrzeby używania cudzysłowów jako argumentu unset.
jarno
2
@jarno: MUSISZ użyć tych cudzysłowów: jeśli masz plik o nazwie array0w bieżącym katalogu, to ponieważ array[0]jest to glob, zostanie on najpierw rozwinięty array0przed komendą unset.
gniourf_gniourf
@gniourf_gniourf masz rację. Powinno to zostać poprawione w podręczniku Bash Reference Manual, który obecnie mówi, że „unset name [indeks] niszczy element tablicy w indeksie indeksu”.
jarno
1

Za pomocą unset

Aby usunąć element pod określonym indeksem, możemy użyć, unseta następnie skopiować do innej tablicy. Tylko unsetw tym przypadku nie jest to wymagane. Ponieważ unsetnie usuwa elementu, po prostu ustawia ciąg pusty na określony indeks w tablicy.

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]}"

Wyjście jest

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

Za pomocą :<idx>

Możemy usunąć jakiś zestaw elementów za pomocą :<idx>również. Na przykład, jeśli chcemy usunąć pierwszy element, możemy użyć, :1jak wspomniano poniżej.

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

Wyjście jest

bb cc dd ee
1st val is cc, 2nd val is dd
rashok
źródło
0

Skrypt powłoki POSIX nie ma tablic.

Więc najprawdopodobniej używasz określonego dialektu, takiego jak bashkorn shells lub zsh.

W związku z tym na twoje pytanie nie można obecnie odpowiedzieć.

Może to działa dla Ciebie:

unset array[$delete]
Has QUIT - Anony-Mousse
źródło
2
Cześć, używam bankomatu bash shell. A „$ delete” nie jest pozycją elementu, ale samym łańcuchem. Więc nie sądzę, że "niesprawny" zadziała
Alex
0

Właściwie właśnie zauważyłem, że składnia powłoki ma pewne wbudowane zachowanie, które pozwala na łatwą rekonstrukcję tablicy, gdy, zgodnie z pytaniem, element powinien zostać usunięty.

# 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

Zauważ, jak zbudowaliśmy tablicę przy użyciu x+=()składni basha ?

W rzeczywistości możesz dodać więcej niż jeden element jednocześnie, zawartość całej innej tablicy.

mar77i
źródło
0

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

$ {PARAMETR # WZÓR} # usuń z początku

$ {PARAMETR ## WZORZEC} # usuń od początku, chciwy mecz

$ {PARAMETR% WZORZEC} # usuń z końca

$ {PARAMETER %% WZORZEC} # usuń z końca, chciwy mecz

Aby wykonać pełne usunięcie elementu, musisz wykonać polecenie unset z instrukcją if. Jeśli nie zależy Ci na usuwaniu prefiksów z innych zmiennych lub obsłudze białych znaków w tablicy, możesz po prostu porzucić cudzysłowy i zapomnieć o pętlach for.

Zobacz poniższy przykład, aby zobaczyć kilka różnych sposobów czyszczenia tablicy.

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

Wynik

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

Mam nadzieję, że to pomoże.

phyatt
źródło
0

W ZSH jest to banalnie proste (zauważ, że używa bardziej składni kompatybilnej z bash niż jest to konieczne, aby ułatwić zrozumienie):

# 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[@]}"

Wyniki:

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
trevorj
źródło
Przepraszam, właśnie próbowałem. To nie działało w zsh dla asoziatywnej tablicy
Falk
Działa dobrze, właśnie to przetestowałem (ponownie). Coś Ci nie pasuje? Proszę wyjaśnić, co nie zadziałało, tak szczegółowo, jak to tylko możliwe. Jakiej wersji ZSH używasz?
trevorj
0

Jest też taka składnia, np. Jeśli chcesz usunąć drugi element:

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

co jest w rzeczywistości połączeniem 2 zakładek. Pierwszy od indeksu 0 do indeksu 1 (wyłączny), a drugi od indeksu 2 do końca.

OphyTe
źródło
-1

Co robię to:

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

BAM, ta pozycja została usunięta.

Garfield
źródło
1
To się psuje array=('first item' 'second item').
Benjamin W.,
-1

Jest to szybkie i brudne rozwiązanie, które będzie działać w prostych przypadkach, ale zepsuje się, jeśli (a) $deletew elementach znajdują się znaki specjalne wyrażenia regularnego lub (b) w jakimkolwiek elemencie są spacje. Począwszy od:

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

Usuń wszystkie wpisy dokładnie pasujące do $delete:

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

w wyniku echo $array-> pippo i upewniając się, że jest to tablica: echo $array[1]-> pippo

fmtjest trochę niejasny: fmt -1zawija w pierwszej kolumnie (aby umieścić każdy element w osobnym wierszu. W tym miejscu pojawia się problem z elementami w fmt -999999spacjach ). rozpakowuje go z powrotem do jednej linii, przywracając odstępy między elementami. Są na to inne sposoby, na przykład xargs.

Dodatek: Jeśli chcesz usunąć tylko pierwsze dopasowanie, użyj seda, jak opisano tutaj :

array=(`echo $array | fmt -1 | sed "0,/^${delete}$/{//d;}" | fmt -999999`)
Joshua Goldberg
źródło
-1

A może coś takiego:

array=(one two three)
array_t=" ${array[@]} "
delete=one
array=(${array_t// $delete / })
unset array_t
user8223227
źródło
-1

Aby uniknąć konfliktów z indeksem tablicy przy użyciu unset - patrz https://stackoverflow.com/a/49626928/3223785 i https://stackoverflow.com/a/47798640/3223785 więcej informacji - przypisanie tablicy do siebie: 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

[Odn .: https://tecadmin.net/working-with-array-bash-script/ ]

Eduardo Lucio
źródło
-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
Gombok Arthur
źródło
1
Czy możesz dodać komentarz lub opis, aby przekazać nam swoją odpowiedź?
Michael