Control multiple SSH sessions from a single interactive shell.
mash connects to multiple remote hosts simultaneously and lets you type commands once to execute them everywhere. It's a Rust reimplementation of polysh that works with my zsh and starship/powerline prompt.
- Parallel SSH sessions — connect to dozens or hundreds of hosts at once
- Interactive multiplexing — type a command, see output from all hosts prefixed with their names
- Host expansion —
mash host<1-50>expands to host1 through host50 - Shell pattern matching —
:enable web*to target specific hosts with glob patterns - Colored output — each host gets a distinct color for easy scanning
- Tab completion — completes commands, paths, hostnames, and history
- Control commands —
:list,:enable,:disable,:reconnect,:rename, and more - Non-interactive mode — pipe commands or use
--commandfor scripting - Password support —
--password-filefor automated password entry - Logging — optional session logging to file
cargo install mash-ssh# Run directly
nix run github:crisidev/mash
# Install into profile
nix profile install github:crisidev/mashgit clone https://github.com/crisidev/mash
cd mash
cargo install --path .# Connect to multiple hosts
mash server1 server2 server3
# Host range expansion
mash web<1-10>
mash db<01-03> cache<1-5>
# Non-interactive: run a command and exit
mash --command "uptime" host<1-20>
# Pipe commands from stdin
echo "hostname && uptime" | mash host<1-5>
# Read hosts from a file
mash --hosts-file servers.txt
# Connect as a specific user
mash --user deploy web<1-10>Once connected, type any command to send it to all enabled shells. Prefix with : for control commands:
mash [● 3] ❯❯❯ uptime # sent to all hosts
mash [● 3] ❯❯❯ :list # show shell status
mash [● 3] ❯❯❯ :disable web3 # stop sending to web3
mash [● 3] ❯❯❯ :enable * # re-enable all
mash [● 3] ❯❯❯ :help # show all commands
mash [● 3] ❯❯❯ !ls # run locally
| Symbol | Color | Meaning |
|---|---|---|
● |
Green | Idle |
◉ |
Yellow | Running |
◌ |
Blue | Pending |
✕ |
Red | Dead |
○ |
Dim | Disabled |
| Command | Description |
|---|---|
:help |
Show help message |
:list [PATTERN] |
List shells and their status |
:quit |
Close all connections and exit |
:enable [PATTERN] |
Enable matching shells |
:disable [PATTERN] |
Disable matching shells |
:reconnect [PATTERN] |
Reconnect dead shells |
:add HOST... |
Add new SSH connections |
:purge [PATTERN] |
Remove disabled shells |
:rename NAME |
Rename enabled shells |
:send_ctrl LETTER [PATTERN] |
Send a control character (e.g. :send_ctrl c) |
:reset_prompt [PATTERN] |
Re-send prompt initialization |
:chdir [PATH] |
Change local working directory |
:hide_password |
Disable echo/debug/logging for password entry |
:set_debug y|n [PATTERN] |
Toggle debug output per shell |
:export_vars |
Set MASH_RANK/NAME/NR_SHELLS on each shell |
:set_log [PATH] |
Set or disable the log file |
:show_read_buffer [PATTERN] |
Show buffered output from shell startup |
PATTERN supports * and ? wildcards matching against shell display names or last output line.
--hosts-file Read hostnames from a file, one per line
--command Command to run on remote shells (non-interactive)
--ssh SSH command template (default: exec ssh -oLogLevel=Quiet -t %(host)s %(port)s)
--user Remote user to log in as
--no-color Disable colored output
--password-file Read password from file (use - for interactive prompt)
--log-file Log session to file
--abort-errors Abort if any shell fails to initialize
--debug Print debug information
mash is a ground-up Rust rewrite of polysh with the same feature set. Key differences:
- Faster startup — compiled binary, no Python interpreter overhead
- Async I/O — tokio-based event loop instead of Python's select()
- Modern shell compatibility — works with zsh + starship/powerlevel10k out of the box
MIT