Published in Articles on by Michiel van Oosterhout ~ 4 min read

In this article we will look at how to configure Bash on Windows. We'll set it up so that Bash included in Cygwin (see Git for Windows revisited), Bash included in Git for Windows (see Installing Git on Windows), and Bash included in a Linux distribution running on WSL (see Windows' Subsystem for Linux) all use the same configuration.

Bash startup files

When a new Bash process starts it will processes certain startup files. Simply stated: an interactive shell will process ~/.bashrc. An interactive login shell will process ~/.bash_profile instead.

Interactive shell

An interactive Bash process (interactive shell) is one which reads from and writes to a terminal (for example, Console Window Host or Windows Terminal). Among other things, an interactive shell displays a prompt, enables command line editing, and expands aliases. When the PS1 variable is set the Bash process is likely interactive.

  • Bash started from another command-line shell is an interactive shell.

Login shell

A login Bash process (login shell) is one which ensures correct initialization of a login session, such as processing certain startup files that should be processed only once per session. In a Bash login shell the login_shell option is set. A login shell is typically interactive.

  • Git Bash started via the Start menu is an interactive login shell (git-bash.exe passes the --login and -i options to Bash).
  • Bash running on WSL started via bash.exe, wsl.exe, or debian.exe is an interactive login shell.

Configuring Bash

We'll need to create the .bash_profile and .bashrc files.

.bash_profile

First we'll create .bash_profile, for login shells. This Bash script will source all Bash scripts found in the $USERPROFILE/.config/bash/login.d directory. This approach ensures we can add new configuration scripts later. After that, the script also sources .bashrc, so that interactive login shells have the same configuration as interactive non-login shells.

# Ensure the directory exists
$path = "$Env:USERPROFILE\.config\bash\login.d"
$_ = New-Item $path -Force -ItemType Directory

# Declare the Bash script contents
$script = @'
dir=${USERPROFILE//\\//}/.config/bash/login.d
if [ -d $dir ]; then
    for file in $dir/*.bash; do
        [ -r $file ] && . $file
    done
fi

file=${USERPROFILE//\\//}/.bashrc
[ -r $file ] && . $file
'@

# Create the Bash script
$path = "$Env:USERPROFILE\.bash_profile"
Set-Content -Path $path -Value $script

# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path

.bashrc

Next we'll create .bashrc, for interactive shells. This Bash script will exit if it is not sourced in an interactive shell, and otherwise it will source all Bash scripts found in the $USERPROFILE/.config/bash/interactive.d directory.

# Ensure the directory exists
$path = "$Env:USERPROFILE\.config\bash\interactive.d"
$_ = New-Item $path -Force -ItemType Directory

# Declare the Bash script contents
$script = @'
[ -z "$PS1" ] && return

dir=${USERPROFILE//\\//}/.config/bash/interactive.d
if [ -d $dir ]; then
    for file in $dir/*.bash; do
        [ -r $file ] && . $file
    done
fi
'@

# Create the Bash script
$path = "$Env:USERPROFILE\.bashrc"
Set-Content -Path $path -Value $script

# Ensure proper line endings
((Get-Content $path) -join "`n") + "`n" | Set-Content -NoNewline $path

WSL

For Bash included in a Linux distribution running on WSL we'll need to do 3 things to ensure it uses the same configuration:

  • Add USERPROFILE to WSLENV
  • Source $USERPROFILE/.bash_profile from ~/.bash_profile
  • Source $USERPROFILE/.bashrc from ~/.bashrc
# Add USERPROFILE to WSLENV
cmd /c setx WSLENV "%WSLENV%:USERPROFILE/pu"

# Source .bash_profile_
wsl echo "[ -r \`"`$USERPROFILE/.bash_profile\`" ] && . \`"`$USERPROFILE/.bash_profile\`"" `> ~/.bash_profile

# Source .bashrd
wsl echo "[ -r \`"`$USERPROFILE/.bashrc\`" ] && . \`"`$USERPROFILE/.bashrc\`"" `> ~/.bashrc

By using the /pu option for the USERPROFILE environment variable, WSL will 'translate' the path to a valid Linux path (e.g. something like /mnt/c/Users/michiel).

Conclusion

With some relatively simple Bash scripts in specific locations it is possible to have single configuration that works for 3 commonly used Bash implementations: Cygwin, Git for Windows, and WSL.