Commando for Bash
An extension system for Bash on Windows
Published in Articles on by Michiel van Oosterhout ~ 3 min read
In a series of 4 articles published in december last year we designed and implemented Commando, an extension system for Windows Command Processor (cmd.exe
). And in the previous article we set up the configuration for Bash on Windows that works for the Bash included in Cygwin, Git for Windows, and WSL. In this article we'll use the configuration setup to implement Commando for Bash.

Commando: a Bash extension system
Unlike PowerShell and its module system, Bash has no built-in extension system. But it does have some extension points in the form of .bash_profile
and .bashrc
. We can use those to create a simple extension system ourselves.
Sourcing the initialization script
In the previous article we configured Bash to source all files from $USERPROFILE/.config/bash/login.d
in a login shell, and all files from $USERPROFILE/.config/bash/interactive.d
in an interactive shell. (In an interactive login shell files from both directores will be sourced.)
So to start with the Commando for Bash implementation we add a script to the interactive.d
directory which will source %LOCALAPPDATA%\Commando\Commando.bash
.
# Add LOCALAPPDATA to WSLENV
cmd /c setx WSLENV "%WSLENV%:LOCALAPPDATA/pu"
# Ensure the directory exists
$path = "$Env:USERPROFILE\.config\bash\interactive.d"
$_ = New-Item $path -Force -ItemType Directory
# Declare the Bash script contents
$script = @'
file=${LOCALAPPDATA//\\//}/Commando/Commando.bash
[ -r $file ] && . $file
'@
# Create the Bash script
$path = "$path\commando.bash"
Set-Content -Path $path -Value $script
# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path
The Windows PowerShell script above ensures WSL is aware of the LOCALAPPDATA
environment variable, and then creates a Bash script in the interactive.d
directory.
Initialization
Upon initialization, Commando for Bash should source all Bash scripts for all extensions, Extend.bash
last, to ensure any functions or aliases declared in such scripts become available and that each extension gets its one-time opportunity to install itself (via Extend.bash
).
The Windows PowerShell script below creates the Commando for Bash initialization script %LOCALAPPDATA%\Commando\Commando.bash
.
# Ensure the directory exists
$path = "$Env:LOCALAPPDATA\Commando"
$_ = New-Item $path -Force -ItemType Directory
# Declare the Bash script contents
$script = @'
dir=$(dirname "${BASH_SOURCE[0]}")
for d in $dir/*; do
if [[ -d "$d" && ! -L "$d" ]]; then
for f in $d/*.bash; do
if [ -r "$f" ]; then
file=$(basename $f)
if [[ "$file" != "Extend.bash" ]]; then
. $f
fi
fi
done
if [ -r "${d}/Extend.bash" ]; then
. "${d}/Extend.bash"
fi
fi
done
'@
# Create the Bash script
$path = "$path\Commando.bash"
Set-Content -Path $path -Value $script
# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path
The Commando for Bash initialization script sources all Bash scripts in all relative sub-directories, Extend.bash
last (if it exists). With this in place, the prompt
function created in Prompt mockups in Git Bash now works without us having to source anything.

prompt
function
Summary
With a proper configuration setup for Bash we were able to implement Commando for Bash with just a few small Bash scripts placed in the right directories.