12

How do I remove all empty strings from a Zsh array?

a=('a' '' 'b' 'c') # remove empty elements from array echo ${(j./.)a} 

Should output a/b/c

    3 Answers 3

    19

    There is the parameter expansion ${name:#pattern} (pattern can be empty), which will work on elements of an array:

    a=('a' '' 'b' 'c') echo ${(j./.)a:#} # If the expansion is in double quotes, add the @ flag: echo "${(@j./.)a:#}" 

    man 1 zshexpn:

    ${name:#pattern} If the pattern matches the value of name, then substitute the empty string; otherwise, just substitute the value of name. If name is an array the matching array elements are removed (use the (M) flag to remove the non-matched elements).

    1
    • +1 the non-klunky way ;)CommentedMay 31, 2020 at 1:06
    10

    That's what zsh does by default when you leave a parameter expansion unquoted¹.

    So:

    a=($a) 

    Will remove the empty elements in the $a array.


    ¹ I generally consider that a misfeature. See the rc/es or fish shells for better arrays that don't do that. That's probably there so as to provide some level of compatibility with the sparse arrays of ksh/bash. ksh/bash arrays not only do empty removal upon unquoted array expansion (written ${a[@]} there), but also split+glob, which means you can't really use arrays unquoted there unless you disable globbing and set $IFS to the empty string (IFS=; set -o noglob; a=(${a[@]}) then does empty removal only there like in zsh in addition to making the array non-sparse)

    3
    • Re ¹: Shame, as that basically means you still have to quote many array expansions just in case, particularly when passing along arguments. I take it there's no option to disable that misfeature?
      – ak2
      CommentedJul 28, 2022 at 12:34
    • 1
      @ak2, not that many as most of the time, at least in my experience, arrays are used for lists of files or in general things other than the empty string. Note that you need "$array[@]" or "${(@)array}", to expand to all the elements including empty ones. "$array" is like "$array[*]" which is the elements joined with the first character of $IFS.CommentedJul 28, 2022 at 12:43
    • Thank you. Luckily, for script/function arguments, there's the still quite concise "$@".
      – ak2
      CommentedJul 28, 2022 at 13:13
    8

    Well, zsh has a :| parameter expansion operator for array subtraction - so a klunky way to do it would be to define a second array consisting of only an empty element

    b=('') 

    and then do

     % echo ${(j./.)a:|b} a/b/c 

    However it feels like there ought to be a way to do it without the additional array

    ... and indeed there is.

      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.