Published in Articles on by Michiel van Oosterhout ~ 4 min read
The prompt of a command-line shell is a good place to display some contextual information, for example the current working directory or the status of the current Git repository. Now that we have Commando for Bash we can start creating some extensions that can be used to add such contextual information to the Bash prompt.
The Bash prompt
Bash gives a lot of control over its prompt. Bash will execute every command in the PROMPT_COMMAND
array before displaying the prompt, and will display the value of the PS1
variable as the primary prompt (and the value of PS2
as the secondary prompt). Certain character sequences, when found in these prompt variables, will be replaced, for example \H
with the hostname or \u
with the username. Parameter expansion and command substitution are also performed on the prompt variables prior to display (unless the promptvars
option is disabled).
Commando extensions for a custom Bash prompt
We are going to create some Commando extensions that each add a command to the PROMPT_COMMAND
array to set a variable holding some contextual information. Such variables can then be used in the PS1
prompt variable. We'll start with some information about the current Git repository.
The GitAt extension
First we'll create a Commando extension to declare a function that can give the information we need. The Windows PowerShell script below creates a new Commando extension called GitAt.
# Ensure the directory exists
$path = "$Env:LOCALAPPDATA\Commando\GitAt"
$_ = New-Item $path -Force -ItemType Directory
# Declare the Bash script contents
$script = @'
function git_at {
# Check that current directory is in a Git repository
if git rev-parse --is-inside-work-tree > /dev/null 2>&1; then
# Get current branch
local result=$(git branch --show-current)
# Get first tag instead
if [ -z "$result" ]; then
result=$(git --no-pager tag --points-at HEAD | head -n 1)
if [ ! -z "$result" ]; then
result="[$result]"
fi
fi
# Get commit ID instead
if [ -z "$result" ]; then
result=$(git rev-parse --short HEAD)
fi
# Echo result
if [ ! -z "$result" ]; then
echo $result
fi
fi
}
'@
# Create the Bash script
$path = "$path\git_at.bash"
Set-Content -Path $path -Value $script
# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path
The extension exports the git_at
function, which checks if the current directory is in a Git repository, and, if so, echo
s the name of the current branch, or the name of the current tag when not on a branch, or the current commit ID.
The GitAt.Prompt extension
We can create another extension that will use the git_at
function to set PROMPT_GIT_AT
every time a prompt is rendered, via an addition to the PROMPT_COMMAND
array.
# Ensure the directory exists
$path = "$Env:LOCALAPPDATA\Commando\GitAt.Prompt"
$_ = New-Item $path -Force -ItemType Directory
# Declare the Bash script contents
$script = @'
PROMPT_COMMAND+=('PROMPT_GIT_AT=$(git_at)')
'@
# Create the Bash script
$path = "$path\Extend.bash"
Set-Content -Path $path -Value $script
# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path
With this extension in place, the PROMPT_GIT_AT
variable is always available for use in the prompt variable.
The Dir.Prompt extension
Because we also want to display the current working directory in the prompt, we'll create one more extension. This one will use the dirs
command to set PROMPT_DIR
every time a prompt is rendered, again via an addition to the PROMPT_COMMAND
array.
# Ensure the directory exists
$path = "$Env:LOCALAPPDATA\Commando\Dir.Prompt"
$_ = New-Item $path -Force -ItemType Directory
# Declare the Bash script contents
$script = @'
PROMPT_COMMAND+=('PROMPT_DIR=$(dirs +0)')
'@
# Create the Bash script
$path = "$path\Extend.bash"
Set-Content -Path $path -Value $script
# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path
With this extension in place, the PROMPT_DIR
variable is always available for use in the prompt variable.
Now we can use the prompt
function (see Prompt mockups in Git Bash) to set a PS1
prompt variable: PS1='\n$(prompt bW "$PROMPT_DIR" / Y- "$PROMPT_GIT_AT") '
.

Setting PS1
automatically
The last remaining piece of the puzzle is to set the PS1
variable automatically. For this we'll add a file to interactive.d
:
# Ensure the directory exists
$path = "$Env:USERPROFILE\.config\bash\interactive.d"
$_ = New-Item $path -Force -ItemType Directory
# Declare the Bash script contents
$script = @'
PS1='\n$(prompt bW "$PROMPT_DIR" / Y- "$PROMPT_GIT_AT") '
'@
# Create the Bash script
$path = "$path\prompt.bash"
Set-Content -Path $path -Value $script
# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path
With this script in place, the Bash prompt is automatically configured at the beginning of any interactive session.

Conclusion
By building small pieces one at a time, we were able to build a larger puzzle. We started with the color
and prompt
functions. Then we set up a configuration system for Bash, which we then used to implement our own extension system, for which we then wrote some extensions. Configuring the prompt was then a simple one-line Bash script.