This document details brush's compatibility with bash, including supported features, known limitations, and how to report issues.
brush aims for high compatibility with bash. We validate this through 1700+ compatibility test cases that compare behavior against bash as an oracle.
Compatibility snapshot: Production-ready for most use cases. Your .bashrc, aliases, functions, and completions should "just work."
if/then/elif/else/ficonditionalsfor,while,untilloops- Arithmetic
forloops:for ((i=0; i<10; i++)) case/esacpattern matching&&,||conditional execution- Subshells
()and command grouping{} - Pipelines and pipeline negation
! - Coprocesses:
coproc { ... }andcoproc NAME { ... }
- Brace expansion:
{a,b,c},{1..10},{a..z} - Parameter expansion:
${var:-default},${var:+set},${var#pattern},${var%pattern},${var//find/replace}, etc. - Command substitution:
$(cmd),`cmd` - Arithmetic expansion:
$((expr)) - Process substitution:
<(cmd),>(cmd) - Tilde expansion:
~,~user - Globbing:
*,?,[...] - Extended globbing:
?(pat),*(pat),+(pat),@(pat),!(pat) globstar:**recursive matching
- I/O:
echo,printf,read,mapfile/readarray - Variables:
declare,local,export,unset,readonly,typeset - Control:
break,continue,return,exit - Navigation:
cd,pushd,popd,dirs,pwd - Jobs:
jobs,fg,bg,wait,kill - Completion:
complete,compgen,compopt - History:
history,fc - Testing:
test,[,[[ - Sourcing & introspection:
.,source,eval,caller - Misc:
alias,unalias,hash,type,command,builtin,enable,help,times,ulimit,umask,trap,shopt,set,shift,getopts
- Indexed arrays:
arr=(a b c),${arr[0]},${arr[@]} - Associative arrays:
declare -A map - Array slicing:
${arr[@]:start:length} - Array operations:
${#arr[@]},${!arr[@]},${!arr[*]}
- Background execution:
cmd & - Suspend/resume: Ctrl+Z,
fg,bg - Job listing:
jobs - Process groups and pipelines
RANDOM,SRANDOMLINENO,FUNCNAME,BASH_SOURCEEPOCHSECONDS,EPOCHREALTIMESECONDSPWD,OLDPWDBASH_VERSINFO,BASH_VERSION
- Compatible with
bash-completion - Git, Docker, systemctl, etc. completions work out of the box
complete,compgen,compoptbuiltins
- Standard:
>,>>,<,2>&1 - Here documents:
<<EOF,<<-EOF(tab-stripped),<<<(here strings) - File descriptor manipulation:
>&n,<&n,n>&m - Process substitution redirects:
>(cmd),<(cmd) - Clobber control:
>|,set -o noclobber
| Status | Feature |
|---|---|
| ✅ | DEBUG trap |
| ✅ | ERR trap |
| ✅ | EXIT trap |
| 🔷 | Signal traps (SIGINT, SIGTERM, etc.) — in progress |
| Status | Feature |
|---|---|
| ✅ | Basic bind support |
| ✅ | bind -x for custom key-bound commands |
| 🔷 | Advanced bind features — in progress |
| Status | Feature |
|---|---|
| ✅ | Common options: errexit, pipefail, extglob, globstar, noclobber, nounset, failglob |
| 🔷 | Less common options — in progress |
These features are on our roadmap but not yet implemented:
The select builtin for creating menu-driven scripts is not yet implemented.
# Not yet supported
select opt in "Option A" "Option B" "Quit"; do
case $opt in
"Option A") echo "A";;
"Option B") echo "B";;
"Quit") break;;
esac
doneThe wait -n option to wait for the next background job to complete is not implemented.
# Not yet supported
job1 &
job2 &
wait -n # Wait for whichever finishes firstThe special variable BASH_COMMAND that contains the currently executing command is currently only available in trap contexts.
These job control builtins are not yet implemented.
These areas have known differences from bash in edge cases. Most users won't encounter these, but they're documented for completeness.
There are ~10 known edge cases where IFS word splitting behavior differs from bash, particularly around:
- Non-whitespace IFS characters and empty field creation
- Mixed whitespace and non-whitespace IFS
- Leading/trailing delimiter handling
Some advanced printf format specifiers behave differently (~8 known cases), particularly features not supported by the underlying uucore library.
- Division by zero handling may differ in
errexitmode $(( exit N ))syntax edge case
Some complex alias expansion scenarios differ from bash (see GitHub issues #57, #286).
- Total test cases: 1700+
- Known failures: ~125
- Most failures are edge cases in IFS handling and printf
The test suite runs on every PR and compares behavior against bash as an oracle.
brush targets compatibility with bash 5.3+. Behavior may differ from older bash versions (3.x, 4.x) in some areas.
Found a script that works in bash but not in brush?
- Check existing issues: GitHub Issues
- Create a minimal reproducer: Reduce to the smallest failing script
- File an issue with:
- The script or command that fails
- Expected behavior (what
bashdoes) - Actual behavior (what
brushdoes) - Your platform (Linux/macOS/etc.)
- GitHub Issues: Track specific compatibility work
- Test Suite: 1700+ tests run on every PR
- This Document: Updated as features are implemented