Rust-based alternatives to traditional Unix shells continue to attract users who want bash compatibility alongside built-in features like syntax highlighting and history-based suggestions. Brush, a bash- and POSIX-compatible shell written in Rust, sits in that group, and version 0.4.0 brings more than 200 merged pull requests representing several months of development.

Bash features filled in
The release closes several long-standing gaps in bash compatibility. Brush now implements set -e (errexit) and pipefail with the same exemption rules bash has accumulated over the years. The set -u (nounset) option errors on unset variable references, including the interaction with ${#arr[i]}. The failglob option treats no-match globs as errors, and the ERR trap is implemented alongside earlier EXIT trap work. Coprocess support via coproc covers both parsing and execution. A new --noglob/-f command-line flag has been added, and unknown command-line options now exit with code 2 to match bash.
Arithmetic handling received attention across high-radix literals, overflow and underflow behavior, the legacy $[expr] syntax, the |= and ^= assignment operators, nested array indices, and infinite-recursion detection. Heredocs are more reliable inside command substitutions and quoted contexts. Builtins including caller, read, mapfile -O, getopts, compgen -A, and printf %q saw fixes or expansions. The maintainer warns that scripts which ran cleanly under v0.3.0 may now exit with errors that bash would also have produced, and treats this as intended behavior.
Platform reach widens
Using brush as a login shell on macOS works after a fix for a startup hang in that scenario. Windows path handling was overhauled, /dev/null emulation was added, and CI now exercises the Windows test suite. FreeBSD builds again, Android and 32-bit targets compile cleanly, and wasm32-wasip2 smoke tests run in CI. Windows support remains experimental.
Interactive features
An opt-in TOML configuration file at ~/.config/brush/config.toml allows brush-specific settings outside shell scripts. Zsh-style preexec and precmd hooks are available behind an experimental flag, useful for prompt frameworks and timing tools. Terminal integration with semantic prompt and command marking can be enabled the same way.
Readline macro support was added with follow-up work to handle real-world inputrc forms, improving compatibility with starship, atuin, and fzf. Completion fixes cover filename escaping, . and .. entries, the mark-directories setting, and COMP_KEY/COMP_TYPE population.
API changes for embedders
The Shell type is now generic over a ShellExtensions parameter, providing a hook for embedders to add custom builtins and variable behavior without forking. Shell fields are private, and serde features are available on both brush-parser and brush-core for AST and shell-state serialization. Scaffolding for a future winnow-based parser has been added, with the existing PEG parser remaining the production code path.
The minimum supported Rust version moves to 1.88. An opt-in build flag bundles coreutils builtins into a single binary, useful for containers, embedded scenarios, and Windows. Brush is distributed under the MIT license through crates.io, Homebrew, Arch Linux’s extra repository, and Nix.
Brush 0.4.0 is available for free on GitHub.

Must read:

Subscribe to the Help Net Security ad-free monthly newsletter to stay informed on the essential open-source cybersecurity tools. Subscribe here!


