Language features compared¶
This page compares what the shell language of dash, bash, zsh and luish can do beyond the basics that all four share: quoting, parameter expansion, arrays, arithmetic, conditionals, globbing, redirections, control flow and the variables the shell sets. Built-in commands compared compares the built-in commands.
Each feature was tried in dash 0.5.12, bash 5.2, zsh 5.9 (started with -f) and luish 0.7.0. The zsh column is
native zsh. Where luish takes a feature from zsh, it usually follows zsh’s sh emulation (zsh --emulate sh), which
turns some of zsh’s features off and counts array indices from 0; the notes say where that matters.
In the tables, ✓ marks a feature that works, – one that doesn’t, and opt one that needs an option turned on.
luish turns on everything that gives a meaning to what is a syntax error in dash, such as a=(x y) or [[, so a
script can use it without any setting. What would change the behaviour of a POSIX script, such as **/ or glob
qualifiers, needs an option, as in bash and zsh.
Quoting¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
✓ |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
– |
In POSIX since 2024 |
|
– |
✓ |
– |
– |
Parameter expansion¶
All four have POSIX’s forms: ${x:-word}, ${x:=word}, ${x:?word}, ${x:+word}, ${#x}, ${x#pattern},
${x##pattern}, ${x%pattern} and ${x%%pattern}.
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
Substrings, |
– |
✓ |
✓ |
✓ |
|
Replacement, |
– |
✓ |
✓ |
✓ |
|
Anchored replacement, |
– |
✓ |
✓ |
✓ |
|
Case, |
– |
✓ |
– |
– |
zsh and luish: |
Transformations, |
– |
✓ |
– |
– |
|
Indirection, |
– |
✓ |
– |
✓ |
zsh: |
Names by prefix, |
– |
✓ |
– |
✓ |
zsh: |
zsh’s flags |
– |
– |
✓ |
✓ |
|
zsh’s other flags, such as |
– |
– |
✓ |
– |
|
Nested, |
– |
– |
✓ |
– |
|
Modifiers, |
– |
– |
✓ |
✓ |
luish has |
Lengths and offsets in characters |
– |
✓ |
✓ |
– |
luish, as dash, counts bytes: in a UTF-8 locale, |
Arrays¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
– |
✓ |
✓ |
✓ |
|
First index |
0 |
1 |
0 |
zsh’s |
|
|
First element |
All elements |
First element |
||
|
– |
✓ |
✓ |
✓ |
|
Holes: |
– |
1 |
5 |
6 |
bash’s arrays are sparse; zsh and luish fill the gap with empty elements |
Indices, |
– |
✓ |
– |
✓ |
|
Slices, |
– |
✓ |
✓ |
✓ |
|
zsh’s ranges, |
– |
– |
✓ |
– |
|
On each element, |
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
|
Read into an array, |
– |
✓ |
✓ |
✓ |
luish takes both |
|
– |
✓ |
– |
– |
|
Exported arrays |
– |
– |
– |
– |
None of them export arrays |
Associative arrays¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
|
Keys, |
– |
✓ |
– |
✓ |
|
Keys, |
– |
– |
✓ |
✓ |
|
Order of the keys |
Hash order |
Hash order |
Insertion order |
Arithmetic¶
All four have $((...)) with C’s integer operators, assignments (x+=2), ?:, hexadecimal (0x10) and octal
(010) numbers.
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
– |
luish: |
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
|
Bases, |
– |
✓ |
✓ |
– |
|
Floating point |
– |
– |
✓ |
– |
|
Integer variables, |
– |
✓ |
✓ |
✓ |
Conditionals¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
✓ |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
zsh: quote it ( |
|
– |
✓ |
✓ |
✓ |
|
Regular expressions, |
– |
✓ |
✓ |
✓ |
luish sets both bash’s |
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
– |
Brace expansion¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
– |
✓ |
✓ |
opt |
luish: |
|
– |
✓ |
✓ |
opt |
|
|
– |
– |
✓ |
opt |
bash expands braces before variables |
Where bash and zsh differ (the sign of a step, {a..e..2}, {1..a}, empty words such as {a,}, > f{1,2}), luish
follows bash (see Compatibility).
Globbing¶
All four have POSIX’s *, ? and [...]. luish sorts matches by bytes, where bash and zsh use the locale’s collation
(the same in the C locale).
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
– |
opt |
✓ |
opt |
bash: |
Glob qualifiers, |
– |
– |
✓ |
opt |
luish: |
ksh’s patterns, |
– |
opt |
opt |
– |
bash: |
zsh’s patterns, |
– |
– |
✓ |
– |
|
No match gives nothing ( |
– |
opt |
opt |
opt |
luish: |
No match is an error ( |
– |
opt |
✓ |
opt |
zsh: |
Error only if no pattern matches ( |
– |
– |
opt |
opt |
luish: |
Matching dot files ( |
– |
opt |
opt |
opt |
luish: |
Redirections and pipes¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
POSIX’s, including |
✓ |
✓ |
✓ |
✓ |
|
File descriptors above 9, |
– |
✓ |
– |
✓ |
dash and zsh read |
Here-strings, |
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
– |
luish, as dash and POSIX, reads |
|
– |
✓ |
✓ |
✓ |
|
Process substitution, |
– |
✓ |
✓ |
✓ |
|
zsh’s |
– |
– |
✓ |
– |
|
Allocated descriptors, |
– |
✓ |
✓ |
– |
|
|
– |
✓ |
✓ |
– |
|
Command substitution without a subshell, |
– |
– |
– |
✓ |
As in bash 5.3 and mksh |
Coprocesses, |
– |
✓ |
✓ |
– |
Control flow and functions¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
– |
✓ |
✓ |
✓ |
|
|
✓ |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
In POSIX since 2024 |
|
– |
✓ |
✓ |
✓ |
luish takes both |
|
– |
✓ |
✓ |
– |
|
|
– |
✓ |
✓ |
– |
|
|
– |
✓ |
✓ |
– |
luish and dash run the |
|
– |
– |
✓ |
– |
|
Anonymous functions, |
– |
– |
✓ |
– |
Errors and debugging¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
✓ |
✓ |
✓ |
✓ |
luish’s |
|
– |
✓ |
✓ |
✓ |
In POSIX since 2024 |
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
– |
|
|
– |
✓ |
✓ |
– |
|
Call stack: |
– |
✓ |
– |
✓ |
zsh has |
The call stack in error messages |
– |
– |
– |
✓ |
bash and zsh name the file (bash) or the function (zsh) of the error, without the calls that led there |
Deep recursion |
Limit for functions (Debian’s), crashes otherwise |
Crashes, unless |
Limit ( |
Error |
luish stops at 1000 levels of function calls, and makes other nesting that would run out of stack an error |
Variables the shell sets¶
Variable |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
opt |
✓ |
zsh: |
|
– |
✓ |
✓ |
✓ |
|
|
– |
✓ |
– |
✓ |
|
|
– |
– |
✓ |
✓ |
|
|
– |
– |
✓ |
✓ |
|
|
– |
✓ |
✓ |
– |
|
|
– |
✓ |
✓ |
✓ |
Variable attributes¶
Feature |
dash |
bash |
zsh |
luish |
Notes |
|---|---|---|---|---|---|
|
✓ |
✓ |
✓ |
✓ |
|
|
– |
✓ |
✓ |
✓ |
|
|
– |
– |
✓ |
✓ |
|
Namerefs, |
– |
✓ |
– |
– |
|
Floating point, |
– |
– |
✓ |
– |
|
Padding, |
– |
– |
✓ |
– |
|
Tied variables, |
– |
– |
✓ |
– |
luish ties only |