Bash dizisinden bir öğeyi kaldırma


116

Bash kabuğundaki bir diziden bir elemanı kaldırmam gerekiyor. Genellikle şunu yapardım:

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

Maalesef kaldırmak istediğim öğe bir değişkendir, bu nedenle önceki komutu kullanamıyorum. Aşağıda bir örnek:

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

Herhangi bir fikir?


Hangi kabuk? Örneğiniz benziyor zsh.
chepner

array=( ${array[@]/$delete} )Bash'de beklendiği gibi çalışır. Sadece kaçırdın mı =?
Ken Sharp

1
@Ken, tam olarak istenen bu değil - her dizeden herhangi bir eşleşmeyi kaldıracak ve tüm dizeyle eşleştiği dizide boş dizeler bırakacaktır.
Toby Speight

Yanıtlar:


165

Aşağıdakiler istediğiniz gibi çalışır bashve zsh:

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

Birden fazla öğeyi silmeniz gerekirse:

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

Uyarı

Bu teknik, aslında $deletetüm öğeleri değil, öğelerle eşleşen önekleri kaldırır .

Güncelleme

Tam bir öğeyi gerçekten kaldırmak için, dizide dolaşmanız, hedefi her öğe ile karşılaştırmanız ve unsettam bir eşleşmeyi silmek için kullanmanız gerekir.

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

Bunu yaparsanız ve bir veya daha fazla öğe kaldırılırsa, endekslerin artık sürekli bir tam sayı dizisi olmayacağını unutmayın.

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

Basit gerçek şu ki, diziler değiştirilebilir veri yapıları olarak kullanılmak üzere tasarlanmamıştır. Öncelikle, bir karakterin sınırlayıcı olarak boşa harcanmasına gerek kalmadan tek bir değişkende öğe listelerini depolamak için kullanılırlar (örneğin, boşluk içerebilen dizelerin bir listesini saklamak için).

Boşluklar bir sorunsa, boşlukları doldurmak için diziyi yeniden oluşturmanız gerekir:

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

43
sadece şunu bilin: $ array=(sun sunflower) $ delete=(sun) $ echo ${array[@]/$delete}sonuçflower
bernstein

12
Bunun aslında bir değiştirme yaptığına dikkat edin, bu nedenle dizi buna benzer bir şeyse, (pluto1 pluto2 pippo)o zaman sonuçlanacaksınız (1 2 pippo).
haridsv

5
Bunu bir for döngüsünde kullanırken dikkatli olun, çünkü silinen öğenin olduğu yerde boş bir öğe ile sonuçlanacaksınız. Akıl sağlığı için şöyle bir şey yapabilirsinizfor element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Joel B

2
Peki sadece eşleşen öğeler nasıl silinir?
UmaN

4
Not: Bu, ilgili değeri hiçbir şeye ayarlayabilir, ancak öğe yine de dizide olacaktır.
phil294

29

İstenmeyen eleman olmadan yeni bir dizi oluşturabilir, ardından onu eski diziye geri atayabilirsiniz. Bu çalışır bash:

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

Bu, şunları verir:

echo "${array[@]}"
pippo

14

Konumunu biliyorsanız, bir değeri silmenin en doğrudan yolu budur.

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

3
Deneyin echo ${array[1]}, boş dizge alacaksınız. Ve almak için threeyapmanız gereken echo ${array[2]}. Bu yüzden unsetbash dizisindeki bir elemanı kaldırmak için doğru mekanizma değildir.
rashok

@rashok, no, ${array[1]+x}null dizedir, yani array[1]unset. unsetkalan elemanların dizinlerini değiştirmez. Unset için argümandan alıntı yapmak gerekli değildir. Bir dizi elemanını yok etmenin yolu Bash kılavuzunda anlatılmıştır .
jarno

@rashok Neden olmasın anlamıyorum. ${array[1]}Sadece boyut 2 olduğu için var olduğunu varsayamazsınız ${!array[@]}. Endeksleri istiyorsanız kontrol edin .
Daniel C. Sobral

4

İşte mapfile ile tek satırlık bir çözüm:

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

Misal:

$ 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

Bu yöntem, grep komutunu değiştirerek / değiştirerek büyük esneklik sağlar ve dizide boş dizeler bırakmaz.


1
Lütfen printf '%s\n' "${array[@]}"o çirkin IFS/ echoşey yerine kullanın .
gniourf_gniourf

Bunun yeni satır içeren alanlarda başarısız olduğunu unutmayın.
gniourf_gniourf

@Socowi Hatalısın, en azından 4.4.19 bash'ta. -d $'\0'sadece -dargüman olmadan mükemmel bir şekilde çalışır .
Niklas Holm

Ah evet, karıştırdım. Afedersiniz. Demek istediğim şuydu: -d $'\0'aynı -d $'\0 something'veya sadece -d ''.
Socowi

$'\0'Yine de netlik için kullanmaktan zarar gelmez
Niklas Holm

4

Bu yanıt, performansın önemli olduğu büyük dizilerden birden çok değerin silinmesi durumuna özgüdür.

En çok oylanan çözümler (1) bir dizide desen değiştirme veya (2) dizi öğeleri üzerinde yineleme. Birincisi hızlıdır, ancak yalnızca farklı öneki olan öğelerle ilgilenebilir, ikincisi O (n * k), n = dizi boyutuna, k = kaldırılacak öğelere sahiptir. İlişkilendirilebilir dizi, göreceli yeni bir özelliktir ve soru ilk gönderildiğinde yaygın olmayabilir.

Tam eşleşme durumu için, büyük n ve k ile, performansı O (n k) 'dan O (n + k log (k))' ye geliştirmek mümkündür. Pratikte, O (n) k'nin n'den çok daha düşük olduğunu varsayar. Hızlandırmanın çoğu, kaldırılacak öğeleri tanımlamak için ilişkilendirilebilir dizi kullanmaya dayanır.

Performans (n ​​dizi boyutu, silinecek k değerleri). Performans, kullanıcı zamanının saniyelerini ölçer

   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%

Beklendiği gibi, currentçözüm N * K'ye doğrusaldır ve fastçözüm pratik olarak K'ya doğrusaldır ve çok daha düşük sabittir. fastÇözelti biraz daha yavaş vs olduğu currentbir çözüm, ek düzenlemesi nedeniyle, k = 1,.

'Hızlı' çözüm: dizi = girdi listesi, sil = kaldırılacak değerlerin listesi.

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

currentEn çok oylanan cevaptan çözüme karşı kıyaslandı.

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

3

İşte bash değişkeninin indireksiyonunu içeren (muhtemelen çok bash'a özgü) küçük bir fonksiyon ve unset; metin ikamesi içermeyen veya boş öğelerin atılmasını içermeyen ve alıntı / boşluk vb. ile herhangi bir sorunu olmayan genel bir çözümdür.

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

delete_ary_elmt ELEMENT ARRAYNAMEHerhangi bir işaret $yokmuş gibi kullanın . Önek eşleşmeleri == $wordiçin == $word*for anahtarını değiştirin ; büyük / ${elmt,,} == ${word,,}küçük harfe duyarlı olmayan eşleşmeler için kullanın ; vb., bash'ın [[desteklediği şey.

Giriş dizisinin dizinlerini belirleyerek ve bunların üzerinde geriye doğru yineleyerek çalışır (böylece öğeleri silmek yineleme sırasını bozmaz). İndisleri elde etmek için, girdi dizisine isme göre erişmeniz gerekir; bu, bash değişkeni yönlendirmesiyle yapılabilir x=1; varname=x; echo ${!varname} # prints "1".

Dizilere isimleriyle erişemezsiniz aryname=a; echo "${$aryname[@]}, bu size bir hata verir. Yapamazsınız aryname=a; echo "${!aryname[@]}", bu size değişkenin indislerini verir aryname(bir dizi olmasa da). İşe aryref="a[@]"; echo "${!aryref}"yarayan şey , dizinin öğelerini yazdıracak, akabuk-sözcük tırnaklarını ve beyaz boşlukları aynen koruyacak echo "${a[@]}". Ancak bu yalnızca bir dizinin öğelerini yazdırmak için işe yarar, uzunluğunu veya dizinlerini yazdırmak için değil ( aryref="!a[@]"veya aryref="#a[@]"veya "${!!aryref}"veya "${#!aryref}"hepsi başarısız olur).

Bu yüzden orijinal diziyi bash indirection ile ismine göre kopyalıyorum ve indisleri kopyadan alıyorum. Endeksleri tersine yinelemek için C-stili bir döngü kullanıyorum. Ayrıca, indislere erişerek ${!arycopy[@]}ve onları ters çevirerek de yapabilirim tac, bu catda giriş satırı sırasını değiştirir.

Değişken dolaylı olmayan bir işlev çözümünün muhtemelen dahil evaledilmesi gerekir ki, bu durumda kullanmak güvenli olabilir veya olmayabilir (söyleyemem).


Bu neredeyse güzel çalışıyor, ancak işleve aktarılan ilk diziyi yeniden açıklamıyor, bu nedenle ilk dizinin değerleri eksik olsa da, dizinleri de karışık. Bunun anlamı, aynı dizide delete_ary_elmt'ye yapacağınız bir sonraki çağrı çalışmayacaktır (veya yanlış şeyleri kaldıracaktır). Örneğin, yapıştırdıklarınızdan sonra, çalıştırmayı delete_ary_elmt "d" arrayve ardından diziyi yeniden yazdırmayı deneyin . Yanlış elemanın kaldırıldığını göreceksiniz. Son öğeyi kaldırmak da asla işe yaramayacaktır.
Scott

2

Yukarıdaki yanıtları genişletmek için, aşağıdakiler, bir diziden birden çok öğeyi kısmi eşleşme olmadan kaldırmak için kullanılabilir:

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

Bu, aşağıdakileri içeren bir dizi ile sonuçlanacaktır: (iki, iki, üç, üç, "bir altı")



1

Yalnızca kısmi yanıt

Dizideki ilk öğeyi silmek için

unset 'array[0]'

Dizideki son öğeyi silmek için

unset 'array[-1]'

@gniourf_gniourf argümanı için tırnak kullanmaya gerek yoktur unset.
jarno

2
@jarno: bu tırnak işaretleri KULLANILMALIDIR: eğer array0mevcut dizinde isimlendirilmiş bir dosyanız varsa , o zaman array[0]glob olduğundan, array0önce unset komutundan önce genişletilecektir .
gniourf_gniourf

@gniourf_gniourf sen haklısın. Bu , şu anda "unset ad [indis] indeks indisindeki dizi elemanını yok eder" yazan Bash Referans Kılavuzu'nda düzeltilmelidir .
jarno

1

kullanma unset

Belirli bir dizindeki bir elemanı kaldırmak için kullanabiliriz unsetve sonra başka bir diziye kopyalayabiliriz. Sadece unsetbu durumda gerekli değildir. Çünkü unsetelemanı kaldırmaz, sadece null dizgeyi dizideki belirli dizine ayarlar.

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

Çıktı

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

kullanma :<idx>

Bazı öğeleri de kullanarak kaldırabiliriz :<idx>. Örneğin 1. elementi kaldırmak istiyorsak :1aşağıda belirtildiği gibi kullanabiliriz .

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

Çıktı

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

0

POSIX kabuk betiğinin dizileri yoktur.

Yani büyük olasılıkla bash, korn kabukları veya gibi belirli bir lehçe kullanıyorsunuz zsh.

Bu nedenle sorunuz şu an için cevaplanamıyor.

Belki bu sizin için işe yarar:

unset array[$delete]

2
Merhaba, bash shell atm kullanıyorum. Ve "$ delete" öğenin konumu değil, dizenin kendisidir. Bu yüzden "ayarlanmadığının" işe yarayacağını düşünmüyorum
Alex

0

Aslında, kabuk sözdiziminin, soruda belirtildiği gibi, bir öğenin kaldırılması gerektiğinde dizinin kolayca yeniden yapılandırılmasına izin veren yerleşik bir davranışa sahip olduğunu fark ettim.

# 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

Bash'in x+=()sözdizimini kullanarak diziyi nasıl oluşturduğumuza dikkat edin ?

Aslında bununla birden fazla öğe ekleyebilirsiniz, tüm diğer dizinin içeriğini aynı anda.


0

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

$ {PARAMETER # PATTERN} # baştan kaldır

$ {PARAMETER ## PATTERN} # baştan kaldır, açgözlü eşleşme

$ {PARAMETER% PATTERN} # sondan kaldır

$ {PARAMETER %% PATTERN} # sondan kaldır, açgözlü eşleşme

Tam bir kaldırma elemanı yapmak için, if ifadesiyle bir unset komutu yapmanız gerekir. Diğer değişkenlerden önekleri kaldırmayı veya dizideki beyaz boşlukları desteklemeyi umursamıyorsanız, tırnak işaretlerini bırakıp döngüleri unutabilirsiniz.

Bir diziyi temizlemenin birkaç farklı yolu için aşağıdaki örneğe bakın.

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

Çıktı

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

Umarım yardımcı olur.


0

ZSH'de bu son derece kolaydır (bunun, anlaşılma kolaylığı için mümkün olduğunda gerekenden daha fazla bash uyumlu sözdizimi kullandığını unutmayın):

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

Sonuçlar:

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

Üzgünüm, yeni denedim. Bir assoziatif dizi için zsh'de çalışmadı
Falk

İyi çalışıyor, sadece test ettim (tekrar). İşler senin için çalışmıyor mu? Lütfen neyin işe yaramadığını olabildiğince ayrıntılı olarak açıklayın. Hangi ZSH sürümünü kullanıyorsunuz?
trevorj

0

Bu sözdizimi de vardır, örneğin 2. elemanı silmek isterseniz:

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

bu aslında 2 sekmenin birleşimidir. 0 dizininden dizin 1'e (hariç) ilk ve dizin 2'den sonuna kadar 2.


-1

Yaptığım şey:

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

BAM, bu öğe kaldırılır.


1
Bu kırılıyor array=('first item' 'second item').
Benjamin W.

-1

Bu, basit durumlarda işe yarayacak, ancak (a) içinde normal ifade özel karakterleri varsa $deleteveya (b) herhangi bir öğede boşluk varsa bozulacak olan hızlı ve kirli bir çözümdür . Şununla başlayarak:

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

Tam olarak eşleşen tüm girişleri silin $delete:

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

echo $array-> pippo ile sonuçlanır ve bir dizi olduğundan emin olun: echo $array[1]-> pippo

fmtbiraz belirsizdir: fmt -1ilk sütunu sarar (her bir öğeyi kendi satırına koymak için. Burada, boşluklardaki öğelerle ilgili sorunun ortaya çıktığı yer.), öğeler arasındaki boşlukları fmt -999999geri koyarak onu bir satıra geri döndürür. Bunu yapmanın başka yolları da var, örneğin xargs.

Ek: Yalnızca ilk eşleşmeyi silmek istiyorsanız, burada açıklandığı gibi sed'i kullanın :

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

-1

Şunun gibi bir şeye ne dersiniz:

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

-1

Kullanılarak dizi indeksi ile çatışmaları önlemek için unset- bkz https://stackoverflow.com/a/49626928/3223785 ve https://stackoverflow.com/a/47798640/3223785 : kendisine diziyi yeniden atama - Daha fazla bilgi için 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
Bize cevabınızı anlatmak için yorum veya açıklama ekleyebilir misiniz?
Michael
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.