9

I'm trying to delete range of array element but it's fail..

My array

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

Print 0-1 array looks ok

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

Now I'm trying to delete only these element using :

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

It's delete whole array..

What I'm doing wrong ?

I found other way of deleting range of array but why above things is not working ?

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

EDIT I had also tried but no luck

unset -v 'a[@]::2' 

    2 Answers 2

    15

    One thing to bear in mind is that bash implemented arrays like ksh, that is as associative arrays where keys are limited to positive integers (contrary to other languages like perl or zsh for instance).

    In:

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

    In bash, you've got an associative array with 3 elements, while in perl, you'd have an array with 790 elements (789 with zsh).

    In ksh or bash, ${a[@]:0:1} returns the first element of the array in the list of elements sorted numerically by key where the key is greater or equal to 0. So in that case, it returns ${a[123]}, not ${a[0]}.

    unset 'a[123]' 

    (remember to quote it, otherwise it would fail if there was a file called a1 or a2 or a3 in the current directory) makes sense, as it removes a particular key in the array.

    unset 'a[@]::2' 

    makes less sense though. bash only understands unset a, unset 'a[123]' or unset 'a[*/@]', anything after is ignored, so unset 'a[@]::2' and unset 'a[@]please' do the same: unset the whole array.

    If you want to unset a range of keys, you'd need to loop through the keys:

    To get the list of keys of the array, the syntax is "${!a[@]}". Unfortunately, applying a range to that doesn't work with bash nor ksh, so you'd need a temporary array:

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

    Now if you want to consider those arrays like in other languages, you don't want to use unset. Like, if the array is not sparse in the first place and you want to keep it so (that is shift all the elements by 2 instead of unsetting the first two), you can do things like:

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

    That is reassign the array with the list of elements you want to keep.

    For comparison, with zsh.

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

    would set an empty value to elements 12 to 16. while unset 'a[16,20]' would shrink the array to 15 elements.

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

    (still with zsh) would shift elements 17 to 20 by 5 positions so a[12] would contain 17.

    1
    2
    1. If your array is continuous/not sparse (all elements from 0..N-1 set)

      You can remove the 2nd element of the array with

      unset 'a[1]' 

      To remove the 2nd, 3rd and 4th element, you can use e.g.

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

      To delete all but the 1st and 2nd element, you can use e.g.

      for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done 
    2. General solution (works also for sparse arrays): You can remove the 2nd element of the array with

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

      To remove the 2nd, 3rd and 4th element, you can use e.g.

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

      To delete all but the 1st and 2nd element, you can use e.g.

      for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done 
    6
    • I already did this n had updated in question.. but question remain about unset a[@]::2CommentedApr 30, 2013 at 16:32
    • 1
      That's wrong in the general case because ${#a[@]} is the number of elements in the array, not the greatest indice in the array (bash arrays, like ksh arrays are sparse, contrary to zsh ones).CommentedApr 30, 2013 at 16:43
    • @StephaneChazelas after deleting element why not reset index ?CommentedApr 30, 2013 at 16:54
    • @StephaneChazelas after doing some RnD I Found this way to reset array a=( $(echo ${a[@]}) ) is this fine ?CommentedApr 30, 2013 at 17:05
    • 2
      @RahulPatil, if you want to unsparse the array, just write it: a=("${a[@]}"), using echo and command substitution would only work in limited corner cases (like when none of the elements are empty or contain spc, tab, NL, backslash, *, ?, [ or start with -).CommentedApr 30, 2013 at 19:40

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.