42

I want to do sth. like this:

foo=(a b c) foo-=b echo $foo # should output "a c" 

How can I remove an entry from an array? foo-=b does not work.

The removal should work no matter where the entry is.

5 Answers 5

44

Gilles second answer is correct if you wish to remove all occurences, but it is a full reassignment of the array and does not address the situation where you wish to remove only a single entry, regardless of duplicates. There is a way in zsh to remove an element from an normal array without reassigning the entire array:

Given the following array:

array=(abc def ghi) 

the following will return the index of the first match for def:

${array[(i)def]} 

and the following format can be used to remove any given indexed value (element index 2 in this example) in an array without reassignment of the entire array:

array[2]=() 

thus, to remove the value def we combine the two:

array[$array[(i)def]]=() 

This is cleaner for single element removal, since there is no explicit array reassignment (cleaner in that any potential side effects, such as the accidental removal of empty items, quoted format issues, etc. are not going to crop up). However Gilles' solution is largely equivalent and has the advantage of multiple matching item removal, if that is what you want. With his method and this method, you have a full toolset for standard array element removal.

Sign up to request clarification or add additional context in comments.

3 Comments

Also relevant: use (I) to remove the last match instead of the first one. Add e to the i/I flag to get an exact match; zsh usually does pattern matching here, ie def* would remove the first element that begins with def.
for more about reassigning/removing array slices, see the Zsh Guide, section 5.4.1 - "Parameter substitution: Using arrays"
This one worked for me to remove an item from the plugins list in zsh 5.9 - Jérôme's answer resulted in an error where oh-my-zsh seemed to be reading the plugins array as a single string.
43

To remove element number $i: a=("${(@)a[1,$i-1]}" "${(@)a[$i+1,$#a]}")

(The simpler construct a=($a[1,$i-1] $a[$i+1,-1]) also removes empty elements.)

ADDED:

To remove any occurence of b: a=("${(@)a:#b}")
:# is the hieroglyph to remove matching elements; "" and (@) is to operate correctly on arrays even if they contain empty elements.

9 Comments

This looks quite complicated. Also, how do I get $i? I just want to remove b.
@Albert: I've added how to remove by content.
Thanks, that addition is exactly what I wanted.
See my answer for a much simpler solution.
shouldn't a=("${(@)a[1,... be a=("${(@)a[0, (starting at 0), since arrays are 0-based indexed?
|
25

Since versions 4.2 and 5.0, zsh accepts ${name:|arrayname} syntax. From manual:

If arrayname is the name (N.B., not contents) of an array variable, then any elements contained in arrayname are removed from the substitution of name.

So, it does exactly what you expect:

$ foo=(a b c) $ excl=(b) $ echo ${foo:|excl} a c 

1 Comment

(@Petr, if you don't mind, I used the syntax mentioned in the zsh manual. I believe it makes sense to keep it. [I don't know how to have a discussion about an edit, I left this comment])
8

foo = (1 2 3)

shift foo

print $foo gives: 2 3

So this removes the first element (is that what you want?)

[edited]

remove the ith element with

foo[$i] =()

instead.

4 Comments

No, I want to remove the entry whereever it is (it is not always at the beginning).
What is $i? How do I get it?
@Dennis: You mean $i=b? That doesn't work. foo(b)=() is not valid.
@Albert: No I mean i=2, which is what the last option in this answer is intended to do. However, it's not what you're looking for.
4

To remove element with content "b" from array:

foo=(a b c) foo=(${foo#b}) 

5 Comments

This will transform (foo bar foobar) into (bar bar)!
No, it doesn't: foo=(foo bar foobar) ; foo=(${foo#bar}) ; echo $foo returns foo foobar.
Incorrect: foo=(a ab ac ad) ; foo=(${foo#a}) ; declare foo gives foo=(b c d) (expected foo=(ab ac ad)).
@TheDoctorWhat He's saying foo#foo not foo#bar.
To clarify, foo=(foo bar foobar barfoo);foo=(${foo#bar});declare foo returns foo=( foo foobar foo ).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.