Parameter expansion flags

Zsh · Expert · 14 min

Flags let zsh do in one expansion what bash needs loops or external tools for.

Zsh puts flags in parentheses right after the opening brace: ${(flags)name}. Several can be combined and expansions nest, with the inner result feeding the outer one.

  • Split and join: (s:,:) splits on a string, (f) splits on newlines (the most common way to turn command output into an array), (j:,:) joins with a separator, (F) joins with newlines.
  • Case: (U) upper, (L) lower, (C) capitalise words.
  • Order and uniqueness: (o) sort ascending, (O) descending, (n) numeric sort, (u) unique.
  • Associative arrays: (k) keys, (v) values, (kv) pairs.
  • Quoting: (q) quotes the value for safe reuse as shell input, (Q) removes one level of quoting.
  • Indirection: (P) treats the value as the name of another parameter.
  • (@) keeps array elements separate inside double quotes, like "${arr[@]}".

Subscript flags search arrays: $arr[(i)value] gives the index of the first match (one past the end if missing), $arr[(r)pattern] the first matching element, (I) and (R) search from the end.

Nesting avoids temporaries: ${${f:t}%%.*} takes the base name, then strips every extension. ${:-text} creates a value from literal text, handy as the innermost expansion. Splitting with (s) drops empty fields unless the expansion is quoted with (@).

Example

csv="b,a,c,a"
parts=(${(s:,:)csv})
print $#parts                       # 4
print ${(j:-:)parts}                # b-a-c-a
print ${(uo)parts}                  # a b c   (unique, sorted)
print ${(U)csv}                     # B,A,C,A
lines=(${(f)"$(printf 'x 1\ny 2\n')"})
print $#lines                       # 2   (split on newlines)
fruits=(apple banana cherry)
print $fruits[(i)banana]            # 2   (index of the element)
print $fruits[(i)kiwi]              # 4   (not found: length + 1)
print $fruits[(r)c*]                # cherry
ref=fruits
print ${(P)ref}                     # apple banana cherry  (indirection)
f=/a/b/archive.tar.gz
print ${${f:t}%%.*}                 # archive  (nested expansion)
s="it's here"
print -r -- ${(q)s}                 # it\'s\ here

Remember

  • ${(s:x:)v} splits, ${(j:x:)arr} joins, (f) splits lines
  • (o) (O) (u) sort and deduplicate; (k) (v) for maps
  • $arr[(i)x] and $arr[(r)pat] search arrays

Watch out for

  • Using plain print to show (q) output: print interprets the backslashes again; use print -r.

Check yourself

  1. What does ${(j:,:)${(s: :)${:-c a b}}} produce?
  2. With arr=(x y z), what is $arr[(i)q]?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: zsh.sourceforge.io/Doc/Release/Expansion.html#Parameter-Expansion-Flags