Hapus elemen dari array Bash

116

Saya perlu menghapus elemen dari array di bash shell. Umumnya saya hanya melakukan:

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

Sayangnya elemen yang ingin saya hapus adalah variabel jadi saya tidak dapat menggunakan perintah sebelumnya. Berikut contohnya:

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

Ada ide?

Alex
sumber
Cangkang yang mana? Contoh Anda terlihat seperti zsh.
chepner
array=( ${array[@]/$delete} )bekerja seperti yang diharapkan di Bash. Apakah Anda melewatkan =?
Ken Sharp
1
@Ken, itu bukan yang diinginkan - itu akan menghapus kecocokan dari setiap string, dan meninggalkan string kosong dalam array yang cocok dengan seluruh string.
Toby Speight

Jawaban:

165

Berikut ini adalah pekerjaan yang Anda inginkan bashdan zsh:

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

Jika perlu menghapus lebih dari satu elemen:

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

Peringatan

Teknik ini sebenarnya menghilangkan pencocokan prefiks $deletedari elemen, tidak harus seluruh elemen.

Memperbarui

Untuk benar-benar menghapus item yang tepat, Anda perlu menelusuri larik, membandingkan target dengan setiap elemen, dan menggunakan unsetuntuk menghapus pencocokan tepat.

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

Perhatikan bahwa jika Anda melakukan ini, dan satu atau lebih elemen dihapus, indeks tidak lagi menjadi urutan bilangan bulat yang berkelanjutan.

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

Fakta sederhananya adalah, array tidak dirancang untuk digunakan sebagai struktur data yang bisa berubah. Mereka terutama digunakan untuk menyimpan daftar item dalam satu variabel tanpa perlu membuang karakter sebagai pembatas (misalnya, untuk menyimpan daftar string yang dapat berisi spasi).

Jika celah menjadi masalah, maka Anda perlu membangun kembali larik untuk mengisi celah tersebut:

for i in "${!array[@]}"; do
    new_array+=( "${array[i]}" )
done
array=("${new_array[@]}")
unset new_array
chepner
sumber
43
ketahuilah bahwa: $ array=(sun sunflower) $ delete=(sun) $ echo ${array[@]/$delete}menghasilkanflower
bernstein
12
Perhatikan bahwa ini sebenarnya melakukan substitusi, jadi jika arraynya seperti itu (pluto1 pluto2 pippo)maka Anda akan berakhir dengan (1 2 pippo).
haridsv
5
Berhati-hatilah menggunakan ini dalam perulangan for karena Anda akan berakhir dengan elemen kosong tempat elemen yang dihapus berada. Untuk kewarasan, Anda dapat melakukan sesuatu sepertifor element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Joel B
2
Jadi bagaimana cara menghapus hanya elemen yang cocok?
UmaN
4
Catatan: ini dapat menyetel nilai masing-masing menjadi tidak ada, tetapi elemennya akan tetap berada dalam larik.
phil294
29

Anda bisa membuat array baru tanpa elemen yang tidak diinginkan, lalu menetapkannya kembali ke array lama. Ini bekerja di bash:

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

Ini menghasilkan:

echo "${array[@]}"
pippo
Steve Kehlet
sumber
14

Ini adalah cara paling langsung untuk menghapus nilai jika Anda mengetahui posisinya.

$ array=(one two three)
$ echo ${#array[@]}
3
$ unset 'array[1]'
$ echo ${array[@]}
one three
$ echo ${#array[@]}
2
signull
sumber
3
Coba echo ${array[1]}, Anda akan mendapatkan string nol. Dan untuk mendapatkan threeyang perlu Anda lakukan echo ${array[2]}. Jadi unsetbukan mekanisme yang tepat untuk menghapus elemen dalam bash array.
rashok
@rashok, tidak, ${array[1]+x}adalah string nol, jadi array[1]tidak disetel. unsettidak mengubah indeks elemen yang tersisa. Mengutip argumen untuk tidak disetel tidak diperlukan. Cara untuk menghancurkan elemen array dijelaskan dalam manual Bash .
jarno
@rashok Saya tidak melihat mengapa tidak. Anda tidak dapat berasumsi bahwa ${array[1]}ada hanya karena ukurannya 2. Jika Anda menginginkan indeks, centang ${!array[@]}.
Daniel C. Sobral
4

Berikut solusi satu baris dengan mapfile:

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

Contoh:

$ 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

Metode ini memungkinkan fleksibilitas tinggi dengan memodifikasi / menukar perintah grep dan tidak meninggalkan string kosong di dalam array.

Niklas Holm
sumber
1
Silakan gunakan printf '%s\n' "${array[@]}"alih-alih benda IFS/ jelek echoitu.
gniourf_gniourf
Perhatikan bahwa ini gagal dengan bidang yang berisi baris baru.
gniourf_gniourf
@Socowi Anda salah, setidaknya pada pesta 4.4.19. -d $'\0'bekerja dengan baik sementara hanya -dtanpa argumen tidak.
Niklas Holm
Ah ya, saya mencampurnya. Maaf. Yang saya maksud adalah: -d $'\0'sama dengan -d $'\0 something'atau adil -d ''.
Socowi
Tidak ada salahnya digunakan $'\0'untuk kejelasan
Niklas Holm
4

Jawaban ini khusus untuk kasus penghapusan beberapa nilai dari array besar, di mana kinerja itu penting.

Solusi yang paling banyak dipilih adalah (1) substitusi pola pada array, atau (2) iterasi atas elemen array. Yang pertama cepat, tetapi hanya dapat menangani elemen yang memiliki awalan berbeda, yang kedua memiliki O (n * k), n = ukuran larik, k = elemen yang akan dihapus. Array asosiatif adalah fitur relatif baru, dan mungkin tidak umum saat pertanyaan pertama kali diposting.

Untuk kasus pencocokan tepat, dengan n dan k besar, mungkin untuk meningkatkan kinerja dari O (n k) ke O (n + k log (k)). Dalam prakteknya, O (n) mengasumsikan k jauh lebih rendah dari n. Sebagian besar percepatan didasarkan pada penggunaan array asosiatif untuk mengidentifikasi item yang akan dihapus.

Performa (ukuran n-array, nilai-k yang akan dihapus). Performa mengukur detik waktu pengguna

   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%

Seperti yang diharapkan, currentpenyelesaiannya linier terhadap N * K, dan fastsolusinya secara praktis linier ke K, dengan konstanta yang jauh lebih rendah. The fastsolusi adalah sedikit lebih lambat vs currentsolusi ketika k = 1, karena pengaturan tambahan.

Solusi 'Cepat': array = daftar input, hapus = daftar nilai yang akan dihapus.

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

Dibandingkan dengan currentsolusi, dari jawaban yang paling banyak dipilih.

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

Berikut adalah fungsi kecil (mungkin sangat spesifik-bash) yang melibatkan tipuan variabel bash dan unset; ini adalah solusi umum yang tidak melibatkan substitusi teks atau membuang elemen kosong dan tidak memiliki masalah dengan kutipan / spasi dll.

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

Gunakan seperti delete_ary_elmt ELEMENT ARRAYNAMEtanpa $sigil. Ganti == $worduntuk == $word*untuk pencocokan awalan; gunakan ${elmt,,} == ${word,,}untuk pencocokan tidak peka huruf besar / kecil; dll., apa pun yang [[didukung bash .

Ia bekerja dengan menentukan indeks dari larik input dan mengulanginya secara terbalik (jadi menghapus elemen tidak mengacaukan urutan iterasi). Untuk mendapatkan indeks, Anda perlu mengakses larik input berdasarkan nama, yang dapat dilakukan melalui indireksi variabel bash x=1; varname=x; echo ${!varname} # prints "1".

Anda tidak dapat mengakses array dengan nama seperti aryname=a; echo "${$aryname[@]}, ini memberi Anda kesalahan. Anda tidak dapat melakukannya aryname=a; echo "${!aryname[@]}", ini memberi Anda indeks variabel aryname(meskipun itu bukan array). Apa yang berhasil aryref="a[@]"; echo "${!aryref}", yang akan mencetak elemen dari array a, mempertahankan kutipan kata-shell dan spasi persis seperti itu echo "${a[@]}". Tapi ini hanya bekerja untuk mencetak elemen array, bukan untuk mencetak panjang atau indeks ( aryref="!a[@]"atau aryref="#a[@]"atau "${!!aryref}"atau "${#!aryref}", mereka semua gagal).

Jadi saya menyalin array asli dengan namanya melalui bash indirection dan mendapatkan indeks dari salinannya. Untuk mengulang indeks secara terbalik, saya menggunakan for loop. Saya juga bisa melakukannya dengan mengakses indeks melalui ${!arycopy[@]}dan membalikkannya dengan tac, yang merupakan catmemutar urutan baris input.

Solusi fungsi tanpa pengaruh variabel mungkin harus terlibat eval, yang mungkin atau mungkin tidak aman untuk digunakan dalam situasi itu (saya tidak tahu).

SVP
sumber
Ini hampir berfungsi dengan baik, namun tidak mendeklarasikan ulang array awal yang diteruskan ke fungsi, jadi meskipun nilai array awal itu hilang, indeksnya juga kacau. Artinya, panggilan berikutnya yang Anda lakukan ke delete_ary_elmt pada larik yang sama tidak akan berfungsi (atau akan menghapus hal yang salah). Misalnya, setelah apa yang telah Anda tempel, coba jalankan delete_ary_elmt "d" arraydan cetak ulang array. Anda akan melihat bahwa elemen yang salah dihapus. Menghapus elemen terakhir juga tidak akan pernah berhasil.
Scott
2

Untuk memperluas jawaban di atas, berikut ini dapat digunakan untuk menghapus beberapa elemen dari larik, tanpa pencocokan parsial:

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

Ini akan menghasilkan larik yang berisi: (dua satu dua tiga tiga empat "satu enam")

Dylan
sumber
2

Jika ada yang menemukan dirinya dalam posisi di mana mereka perlu mengingat nilai set -e atau set -x dan dapat memulihkannya, lihat inti ini yang menggunakan solusi penghapusan array pertama untuk mengelola tumpukannya sendiri:

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

Konstantin Gredeskoul
sumber
1

Jawaban parsial saja

Untuk menghapus item pertama dalam larik

unset 'array[0]'

Untuk menghapus item terakhir dalam larik

unset 'array[-1]'
consideRatio
sumber
@gniourf_gniourf tidak perlu menggunakan tanda kutip untuk argumen unset.
jarno
2
@jarno: tanda kutip ini HARUS digunakan: jika Anda memiliki file bernama array0di direktori saat ini, maka karena array[0]adalah glob, itu akan diperluas terlebih dahulu array0sebelum perintah unset.
gniourf_gniourf
@gniourf_gniourf Anda benar. Ini harus diperbaiki dalam Bash Reference Manual yang saat ini mengatakan "unset name [subskrip] menghancurkan elemen array pada subskrip indeks".
jarno
1

Menggunakan unset

Untuk menghapus elemen pada indeks tertentu, kita dapat menggunakan unsetdan kemudian menyalin ke array lain. Hanya saja unsettidak diperlukan dalam kasus ini. Karena unsettidak menghapus elemen itu hanya menetapkan string null ke indeks tertentu dalam array.

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

Outputnya adalah

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

Menggunakan :<idx>

Kami juga dapat menghapus beberapa set elemen menggunakan :<idx>. Misalnya jika kita ingin menghapus elemen pertama kita dapat menggunakan :1seperti yang disebutkan di bawah ini.

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

Outputnya adalah

bb cc dd ee
1st val is cc, 2nd val is dd
rashok
sumber
0

Skrip shell POSIX tidak memiliki larik.

Jadi, kemungkinan besar Anda menggunakan dialek tertentu seperti bash, korn shells atau zsh.

Oleh karena itu, pertanyaan Anda sampai saat ini tidak dapat dijawab.

Mungkin ini berhasil untuk Anda:

unset array[$delete]
Memiliki QUIT - Anony-Mousse
sumber
2
Hai, saya menggunakan bash shell atm. Dan "$ delete" bukanlah posisi elemen tetapi string itu sendiri. Jadi menurut saya "tidak disetel" akan berhasil
Alex
0

Sebenarnya, saya baru saja memperhatikan bahwa sintaks shell agak memiliki perilaku built-in yang memungkinkan rekonstruksi larik dengan mudah ketika, seperti yang diajukan dalam pertanyaan, sebuah item harus dihapus.

# 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

Perhatikan bagaimana kita membangun array menggunakan bash's x+=() sintaks ?

Anda sebenarnya dapat menambahkan lebih dari satu item dengan itu, konten dari seluruh larik lainnya sekaligus.

mar77i
sumber
0

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

$ {PARAMETER # PATTERN} # hapus dari awal

$ {PARAMETER ## PATTERN} # hapus dari awal, pertandingan serakah

$ {PARAMETER% PATTERN} # hapus dari bagian akhir

$ {PARAMETER %% PATTERN} # hapus dari akhir, pertandingan serakah

Untuk melakukan elemen hapus penuh, Anda harus melakukan perintah unset dengan pernyataan if. Jika Anda tidak peduli tentang menghapus prefiks dari variabel lain atau tentang mendukung whitespace dalam larik, maka Anda dapat melepaskan tanda kutip dan melupakan untuk loop.

Lihat contoh di bawah untuk beberapa cara berbeda untuk membersihkan larik.

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

Keluaran

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

Semoga membantu.

phyatt.dll
sumber
0

Di ZSH ini sangat mudah (perhatikan ini menggunakan sintaks yang lebih kompatibel dengan bash daripada yang diperlukan jika memungkinkan untuk kemudahan pemahaman):

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

Hasil:

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
sumber
Maaf, baru mencoba. Itu tidak bekerja di zsh untuk array assoziative
Falk
Ini berfungsi dengan baik, saya baru saja mengujinya (lagi). Ada hal yang tidak berhasil untuk Anda? Tolong jelaskan apa yang tidak berhasil sedetail mungkin. Versi ZSH apa yang Anda gunakan?
trevorj
0

Ada juga sintaks ini, misalnya jika Anda ingin menghapus elemen ke-2:

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

yang merupakan gabungan dari 2 tab. Yang pertama dari indeks 0 ke indeks 1 (eksklusif) dan yang ke-2 dari indeks 2 sampai akhir.

OphyTe
sumber
-1

Yang saya lakukan adalah:

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

BAM, item itu dihapus.

garfield
sumber
1
Ini istirahat untuk array=('first item' 'second item').
Benjamin W.
-1

Ini adalah solusi cepat dan kotor yang akan berfungsi dalam kasus sederhana tetapi akan rusak jika (a) ada karakter khusus regex di $delete, atau (b) ada spasi sama sekali di item mana pun. Dimulai dengan:

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

Hapus semua entri yang sama persis $delete:

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

menghasilkan echo $array-> pippo, dan pastikan itu adalah array: echo $array[1]-> pippo

fmtagak kabur: fmt -1membungkus di kolom pertama (untuk meletakkan setiap item di barisnya sendiri. Di situlah masalah muncul dengan item dalam spasi.) fmt -999999membukanya kembali ke satu baris, meletakkan kembali spasi di antara item. Ada cara lain untuk melakukannya, sepertixargs .

Tambahan: Jika Anda hanya ingin menghapus kecocokan pertama, gunakan sed, seperti yang dijelaskan di sini :

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

Bagaimana dengan sesuatu seperti:

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

Untuk menghindari konflik dengan indeks array menggunakan unset- lihat https://stackoverflow.com/a/49626928/3223785 dan https://stackoverflow.com/a/47798640/3223785 untuk informasi lebih lanjut - menetapkan kembali array untuk dirinya sendiri: 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/ ]

Eduardo Lucio
sumber
-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
sumber
1
Dapatkah Anda menambahkan beberapa komentar atau deskripsi untuk memberi tahu kami tentang jawaban Anda?
Michael