Pasting bash snippets into zsh (or the reverse) breaks in subtle ways unless you know these differences.
Zsh scripts look like bash scripts, but several defaults differ:
- No word splitting of unquoted variables. With
v="a b",$vstays one word. Use${=v}to split explicitly, orsetopt SH_WORD_SPLIT. Globs inside variable values are not expanded either unless you write${~v}. - Arrays are 1-based:
$arr[1]is the first element,$arr[-1]the last,$#arrthe length,$arr[2,3]a slice.$arralone gives all elements, and empty elements are dropped unless you use"${arr[@]}". - Associative arrays:
typeset -A m;${(k)m}lists keys,${(v)m}values. read -A(not-a) reads words into an array.- The last stage of a pipeline runs in the current shell, so
cmd | read vsetsv. - An unmatched glob is an error (
NOMATCH); use(N).
Prefer print over echo (print -r -- for raw output, print -l one argument per line); like zsh's echo, plain print interprets backslash escapes.
For code that must behave like sh or ksh, emulate -L sh inside a function switches to those rules for that function only (-L makes options local). Conversely, libraries meant to work under any user configuration start with emulate -L zsh to get default zsh options.
Example
words="one two three"
for w in $words; do print -- "<$w>"; done # <one two three>
for w in ${=words}; do print -n -- "<$w>"; done; print # <one><two><three>
arr=(alpha beta gamma)
print $arr[1] $arr[-1] $#arr # alpha gamma 3 (1-based)
print $arr[2,3] # beta gamma
typeset -A port=(http 80 https 443)
print $port[https] # 443
print ${(k)port} # https http (order not guaranteed)
echo hi | read v; print "v=$v" # v=hi (in bash: v=)
read -A parts <<< "x y z"; print $#parts # 3
f() { emulate -L sh; s="a b"; set -- $s; print $#; }
f # 2 (sh rules: word splitting on)
print -l -- *.nomatch(N) done # doneRemember
- Unquoted $var is not split in zsh; ${=var} splits explicitly
- Arrays start at 1; $#arr is the length
- emulate -L sh or zsh sets predictable rules inside a function
Watch out for
- Porting a bash loop over
$listand getting a single iteration because zsh does not split it.