This guide helps users transition from pdsh to bssh while maintaining existing workflows and scripts.
- Why Migrate to bssh?
- Compatibility Overview
- Installation
- Enabling pdsh Compatibility Mode
- Command Migration
- Feature Comparison
- Known Differences
- Migration Checklist
- Troubleshooting
bssh provides several advantages over pdsh:
- Modern Architecture: Built with Rust for memory safety and performance
- Enhanced Features: Interactive TUI, real-time progress tracking, SSH agent support
- Active Development: Regular updates and security patches
- Cross-Platform: Native support for Linux and macOS
- Full pdsh Compatibility: Drop-in replacement with compatibility mode
- Better Error Handling: Detailed error messages and graceful failure handling
bssh provides three ways to run in pdsh compatibility mode:
- Symlink (recommended for full compatibility)
- Environment variable
- CLI flag
All three methods enable the same pdsh-compatible behavior, mapping pdsh options to their bssh equivalents automatically.
# Install bssh via Homebrew
brew tap lablup/tap
brew install bssh
# Create pdsh symlink (done automatically by Homebrew)
# The symlink is created at: /usr/local/bin/pdsh -> /usr/local/bin/bssh# Add the PPA and install
sudo add-apt-repository ppa:lablup/backend-ai
sudo apt update
sudo apt install bssh
# Create pdsh symlink manually
sudo ln -sf $(which bssh) /usr/local/bin/pdsh# Download and install .deb package
wget https://github.com/lablup/bssh/releases/download/vVERSION/bssh_VERSION_OS_ARCH.deb
sudo dpkg -i bssh_VERSION_OS_ARCH.deb
# Create pdsh symlink
sudo ln -sf $(which bssh) /usr/local/bin/pdsh# Build from source
cargo build --release
sudo cp target/release/bssh /usr/local/bin/
# Create pdsh symlink
sudo ln -s /usr/local/bin/bssh /usr/local/bin/pdsh# Check that pdsh points to bssh
which pdsh
# Output: /usr/local/bin/pdsh
ls -l $(which pdsh)
# Output: /usr/local/bin/pdsh -> /usr/local/bin/bssh
# Verify version
pdsh --version
# Output: bssh X.Y.Z (in pdsh compatibility mode)Create a symlink named pdsh pointing to bssh. This is the most transparent method and requires no script modifications.
# System-wide installation
sudo ln -sf $(which bssh) /usr/local/bin/pdsh
# User installation (in $HOME/bin or similar)
ln -sf $(which bssh) ~/bin/pdshWith the symlink in place, all your existing pdsh commands work unchanged:
pdsh -w host1,host2,host3 "uptime"
# Automatically runs in pdsh compatibility modeSet BSSH_PDSH_COMPAT=1 to enable pdsh mode without a symlink:
# For a single command
BSSH_PDSH_COMPAT=1 bssh -w host1,host2 "uptime"
# Export for the entire session
export BSSH_PDSH_COMPAT=1
bssh -w host1,host2 "uptime"
# Add to shell configuration for permanent enablement
echo 'export BSSH_PDSH_COMPAT=1' >> ~/.bashrcUse the --pdsh-compat flag explicitly:
bssh --pdsh-compat -w host1,host2 "uptime"For users who prefer aliases over symlinks:
# Bash/Zsh
echo 'alias pdsh="bssh --pdsh-compat"' >> ~/.bashrc
# or
echo 'alias pdsh="bssh --pdsh-compat"' >> ~/.zshrc
# Fish
echo 'alias pdsh="bssh --pdsh-compat"' >> ~/.config/fish/config.fish
# Reload shell configuration
source ~/.bashrc # or ~/.zshrc| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w host1,host2 "cmd" |
Same | Works unchanged with symlink |
pdsh -w host[1-5] "cmd" |
Same | Hostlist expressions supported |
pdsh -w ^/etc/hosts.list "cmd" |
Same | File input supported |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -f 10 "cmd" |
Same | -f maps to --parallel |
pdsh -w hosts -f 1 "cmd" |
Same | Sequential execution |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w host[1-10] -x host5 "cmd" |
Same | Direct mapping |
pdsh -w hosts -x "bad*" "cmd" |
Same | Glob patterns supported |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -l admin "cmd" |
Same | -l works identically |
pdsh -w user@host "cmd" |
Same | User@host syntax supported |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -t 30 "cmd" |
Same | Connect timeout (seconds) |
pdsh -w hosts -u 600 "cmd" |
Same | Command timeout (seconds) |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -N "cmd" |
Same | Disable hostname prefix |
pdsh -w hosts "cmd" | dshbak |
Use --stream or TUI |
bssh has built-in formatting |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -q |
Same | Show target hosts and exit |
pdsh -w hosts -x "bad*" -q |
Same | Query with exclusions |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -b "cmd" |
Same | Single Ctrl+C terminates |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -k "cmd" |
Same | Stop on first failure |
| pdsh Command | bssh Equivalent | Notes |
|---|---|---|
pdsh -w hosts -S "cmd" |
Same | Return largest exit code |
| Feature | pdsh | bssh | Notes |
|---|---|---|---|
| Basic command execution | ✅ | ✅ | Identical behavior |
| Hostlist expressions | ✅ | ✅ | host[1-5], rack[1-2]-node[1-3] |
| Host exclusion | ✅ | ✅ | -x with glob patterns |
| Fanout control | ✅ | ✅ | -f for parallel connections |
| User specification | ✅ | ✅ | -l user option |
| Timeouts | ✅ | ✅ | Connect and command timeouts |
| Query mode | ✅ | ✅ | -q to list hosts |
| Batch mode | ✅ | ✅ | -b for single Ctrl+C |
| Fail-fast mode | ✅ | ✅ | -k to stop on failure |
| No prefix output | ✅ | ✅ | -N flag |
| Feature | Description |
|---|---|
| Interactive TUI | Real-time multi-node monitoring with Summary/Detail/Split/Diff views |
| Progress Tracking | Automatic detection of progress indicators (%, fractions, apt/dpkg) |
| SSH Agent Support | Native SSH agent authentication |
| Jump Hosts | ProxyJump support for bastion hosts |
| Port Forwarding | Local, remote, and dynamic (SOCKS) forwarding |
| Configuration Files | YAML-based cluster configuration |
| Modern Output Modes | TUI, stream, file, and normal modes with auto-detection |
| Exit Code Strategies | Multiple strategies for handling node failures |
| Sudo Password Injection | Automatic sudo password handling |
| Backend.AI Integration | Auto-detection of Backend.AI multi-node sessions |
| Feature | Alternative in bssh |
|---|---|
| RCMD modules (rsh, ssh, mrsh) | bssh uses SSH only (more secure) |
| GENDERS integration | Use YAML config files |
| dshbak output collation | Use --stream mode or built-in TUI |
| SLURM/TORQUE integration | Use host lists or config files |
- pdsh: Default fanout is 32
- bssh: Default parallel is 10 (native mode), 32 (pdsh mode)
Migration: When using pdsh compatibility mode, bssh automatically uses fanout=32 to match pdsh behavior.
- pdsh: Plain text with optional dshbak post-processing
- bssh: Advanced TUI with real-time updates (when running in terminal)
Migration:
- Use
--streamflag for pdsh-like plain output - Use
-Nfor no hostname prefix (matches pdsh behavior) - Pipe to file/command to disable TUI auto-detection
# Plain output like pdsh
pdsh -w hosts --stream "cmd"
# Or disable TUI by piping
pdsh -w hosts "cmd" | cat- pdsh: Supports multiple RCMD modules (ssh, rsh, mrsh, qsh)
- bssh: SSH only (more secure, widely available)
Migration: Ensure all target hosts support SSH. bssh will not work with rsh-based hosts.
- pdsh: Returns 0 on success, 1 if any host fails
- bssh: Returns main rank exit code by default (v1.2.0+), supports multiple strategies
Migration:
- Add
--require-all-successflag for pdsh-like behavior - Or use
-S(equivalent to--any-failure) to return largest exit code
# pdsh-style behavior (fail if any host fails)
pdsh -w hosts --require-all-success "cmd"
# Return largest exit code from any host
pdsh -w hosts -S "cmd"- pdsh: Uses GENDERS, SLURM, or flat files
- bssh: Uses YAML configuration files
Migration: Convert cluster definitions to YAML format:
# ~/.config/bssh/config.yaml
clusters:
production:
nodes:
- web1.example.com
- web2.example.com
- web3.example.com
user: admin
ssh_key: ~/.ssh/prod_keyThen use with -C flag:
# Using config file
bssh -C production "uptime"
# Still works with -w
pdsh -w web[1-3].example.com "uptime"- Identify all scripts and tools using pdsh
- Test bssh with pdsh compatibility mode on non-production hosts
- Verify all target hosts support SSH (not rsh/mrsh)
- Check for GENDERS/SLURM integration (migrate to YAML config)
- Review custom pdsh wrappers and automation
- Install bssh via preferred method (Homebrew, apt, cargo)
- Create pdsh symlink (
ln -sf $(which bssh) /usr/local/bin/pdsh) - Verify symlink:
which pdshshould point to bssh - Test basic command:
pdsh -w localhost "echo test"
- Convert GENDERS files to bssh YAML format
- Migrate cluster definitions to
~/.config/bssh/config.yaml - Test cluster access:
bssh -C <cluster> "uptime" - Configure SSH keys and authentication methods
- Set up any required environment variables
- Audit all scripts for pdsh usage
- Test scripts with pdsh symlink (should work unchanged)
- Update scripts using dshbak to use
--streamor TUI - Add
--require-all-successflag where needed - Update documentation and comments
- Test basic command execution across all clusters
- Verify fanout/parallel behavior
- Test host exclusion patterns
- Validate timeout behavior
- Check query mode functionality
- Test error handling and exit codes
- Verify batch mode and fail-fast behavior
- Monitor for any edge cases or unexpected behavior
- Update team documentation and runbooks
- Train team members on bssh-specific features (TUI, config files)
- Consider removing old pdsh installations
- Document any bssh-specific optimizations
Problem: Running pdsh doesn't invoke bssh
Solution:
# Check if symlink exists and is correct
ls -l $(which pdsh)
# Recreate symlink
sudo ln -sf $(which bssh) /usr/local/bin/pdsh
# Ensure /usr/local/bin is in PATH
echo $PATH | grep -o '/usr/local/bin'Problem: pdsh: error: unrecognized option: -w
Solution: Ensure pdsh compatibility mode is active:
# Check if running in compatibility mode
pdsh --version
# Should show: "bssh X.Y.Z (pdsh compatibility mode)" or similar
# Manually enable compatibility mode
BSSH_PDSH_COMPAT=1 bssh -w hosts "cmd"Problem: Output looks different from pdsh
Solution:
# Use stream mode for plain output
pdsh -w hosts --stream "cmd"
# Disable hostname prefix
pdsh -w hosts -N "cmd"
# Pipe to disable TUI
pdsh -w hosts "cmd" | catProblem: host[1-5] not expanding properly
Solution: Ensure compatibility mode is enabled and check syntax:
# Query mode to verify expansion
pdsh -w "host[1-5]" -q
# Should output:
# host1
# host2
# host3
# host4
# host5Problem: Exit codes don't match pdsh expectations
Solution:
# Add --require-all-success for pdsh-like behavior
pdsh -w hosts --require-all-success "cmd"
# Or use -S to return largest exit code
pdsh -w hosts -S "cmd"Problem: SSH authentication fails
Solution:
# Enable SSH agent
pdsh -A -w hosts "cmd"
# Use specific SSH key
pdsh -i ~/.ssh/key -w hosts "cmd"
# Enable verbose logging
pdsh -vv -w hosts "cmd"Problem: bssh seems slower than pdsh
Solution:
# Increase parallel connections
pdsh -w hosts -f 50 "cmd"
# Use stream mode instead of TUI
pdsh -w hosts --stream "cmd"
# Check connection timeout
pdsh -w hosts -t 10 "cmd"Problem: pdsh -w ^/path/to/hosts doesn't work
Solution: This feature may not be supported in the same way. Use:
# Alternative: Read hosts and pass directly
HOSTS=$(cat /path/to/hosts | tr '\n' ',' | sed 's/,$//')
pdsh -w "$HOSTS" "cmd"
# Or use bssh config file
bssh -C cluster-name "cmd"- Documentation: https://github.com/lablup/bssh/blob/main/README.md
- Issue Tracker: https://github.com/lablup/bssh/issues
- Architecture Guide: https://github.com/lablup/bssh/blob/main/ARCHITECTURE.md
- Option Mapping: See pdsh-options.md
- Examples: See pdsh-examples.md
- Open an issue on GitHub for bugs or feature requests
- Check existing issues for known problems and workarounds
- Contribute improvements via pull requests
When reporting issues, please include:
- bssh version:
bssh --version - Compatibility mode status: How pdsh mode was enabled (symlink/env/flag)
- Command that failed: Full command line
- Expected vs actual behavior
- Error messages: Include full error output
- Environment: OS, shell, SSH version
Example bug report:
**Version**: bssh 1.4.0
**Mode**: pdsh symlink (/usr/local/bin/pdsh -> /usr/local/bin/bssh)
**Command**: pdsh -w host[1-3] -f 10 "uptime"
**Expected**: Output from 3 hosts
**Actual**: Error: "failed to parse hostlist expression"
**Error**: <paste full error>
**Environment**: Ubuntu 22.04, bash 5.1.16, OpenSSH 8.9p1
Note: This migration guide is maintained as part of the bssh project. For the latest version, see https://github.com/lablup/bssh/blob/main/docs/pdsh-migration.md