Files
bash-for-windows/README.md
2026-05-31 21:49:13 +02:00

5.7 KiB

bash-for-windows

A bash-compatible shell for Windows, written in Go. Runs natively as a single .exe — no WSL, Cygwin, or MSYS2 required.

Install

Build first, then run the installer:

./build.sh --release     # produces release/bash.exe + installer scripts

Copy the release/ folder to your Windows machine, then double-click install.bat.

The installer:

  • Copies bash.exe to %LOCALAPPDATA%\Programs\BashForWindows\
  • Adds it to your user PATH
  • Registers a "Bash for Windows" profile in Windows Terminal so it shows up in the + dropdown
# Optional flags
.\install.ps1 -InstallDir "C:\Tools\bash"   # custom install path
.\install.ps1 -NoTerminal                   # skip Windows Terminal profile
.\install.ps1 -Uninstall                    # clean removal

Features

Shell language

  • Control flowif/elif/else/fi, for/do/done, while/until
  • Functionsname() { ... } and function name { ... }, with local/return
  • Arithmetic$(( expr )), $((i + 1)), $((n % 2))
  • Command substitution$(cmd), including pipelines: x=$(echo foo | tr a-z A-Z)
  • Variable expansion$VAR, ${VAR}, ${VAR:-default}, ${VAR:=val}, ${#VAR}, ${VAR%suffix}, ${VAR#prefix}
  • Glob expansion*.txt, src/**
  • Tilde expansion~/Documents
  • Quotes — single 'literal', double "with $vars", backslash escapes
  • Inline commentsecho hello # this is ignored

I/O

  • Pipelinescmd1 | cmd2 | cmd3
  • Redirection>, >>, <, 2>, 2>&1, &>
  • Background jobscmd &
  • Command chaining&&, ||, ;

Interactive

  • Command history with arrow keys (saved to ~/.bash_history)
  • Tab completion for commands and file paths
  • Multi-line inputif/for/while/functions continue on the next line
  • Prompt shows current directory and last exit code when non-zero

Built-in commands

Category Commands
Shell cd, pwd, echo, exit, export, set, unset, source/., alias, unalias, type, command, which, env
Control true, false, test/[, break, continue, return, shift, read, printf
Variables declare, local
Files ls, cat, cp, mv, rm, mkdir, touch, find, basename, dirname
Text grep, sed, sort, uniq, wc, head, tail, cut, tr, tee, xargs
System date, sleep, clear, jobs

Usage

bash                  # interactive shell
bash -c 'echo hello'  # run a command string
bash script.sh        # run a script file
bash script.sh arg1   # pass arguments ($1, $2, ...)

Running bash scripts

Any file with a #!/usr/bin/env bash or #!/bin/bash shebang is automatically detected and executed through bash-for-windows — no need to invoke bash explicitly.

Run by passing the path directly:

bash myscript.sh
bash myscript          # extension is optional
bash C:\scripts\deploy.sh production

Or put the script on PATH and call it by name:

If the script is in a directory that is on your PATH (e.g. the bash-for-windows install directory), you can call it directly from the interactive shell or from PowerShell:

waifufetch
waifu
deploy

Bash-for-windows detects the shebang, runs the script through its own interpreter, and passes any arguments as $1, $2, etc.

CRLF line endings are handled automatically. Scripts checked out on Windows often have \r\n line endings. Bash-for-windows strips the carriage returns before executing, so #!/usr/bin/env bash\r in the shebang line never causes the env: 'bash\r': No such file or directory error you get with WSL.

Adding a script to PATH:

The easiest place to drop scripts is the same directory bash-for-windows is installed in:

$d = "$env:LOCALAPPDATA\Programs\BashForWindows"
Copy-Item .\myscript $d\myscript

That directory is already on PATH after running install.ps1, so the script is immediately callable from any shell.

Examples

# Variables and arithmetic
name="World"
echo "Hello $name"
echo $((40 + 2))

# Loops and functions
is_even() {
    if [ $(($1 % 2)) -eq 0 ]; then return 0; else return 1; fi
}
for n in 1 2 3 4 5 6; do
    if is_even $n; then echo "$n is even"; fi
done

# Pipelines and redirection
printf "127.0.0.1 localhost\n127.0.0.2 example\n" | grep localhost | wc -l
find . -name "*.go" | xargs grep "TODO" > todo_files.txt
echo "result=$(date)" >> log.txt

Build from source

Requires Go 1.21+.

./build.sh              # builds Linux debug + Windows .exe into build/
./build.sh --release    # also creates release/ folder ready to distribute
# Manual cross-compile
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o bash.exe .

Project layout

cmd/bash/            entry point, readline REPL
internal/shell/
  shell.go           Execute, parseBlocks, splitStatements, IsIncomplete
  expand.go          expandWord, tokenize, arithmetic, glob
  exec.go            pipelines, redirections, external commands
  control.go         if/for/while/until, function define/call
  builtins.go        all built-in commands and coreutils
install.ps1          Windows installer (PATH + Windows Terminal profile)
install.bat          double-click wrapper for install.ps1
build.sh             build script

License

MIT

NOTE:

Just because this is a port of Bash does not mean every Linux/Unix command will work out of the box. While the core Bash syntax, logic, and a set of built-in commands have been implemented, any external command requires either a native Windows executable or a dedicated port to function.