Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:28:57 +08:00
commit 99185c0a7c
16 changed files with 10488 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,992 @@
# Common Bash Patterns and Anti-Patterns
Collection of proven patterns and common mistakes in bash scripting with explanations and solutions.
---
## Table of Contents
1. [Variable Handling](#variable-handling)
2. [Command Execution](#command-execution)
3. [File Operations](#file-operations)
4. [String Processing](#string-processing)
5. [Arrays and Loops](#arrays-and-loops)
6. [Conditionals and Tests](#conditionals-and-tests)
7. [Functions](#functions)
8. [Error Handling](#error-handling)
9. [Process Management](#process-management)
10. [Security Patterns](#security-patterns)
---
## 🚨 CRITICAL GUIDELINES
### Windows File Path Requirements
**MANDATORY: Always Use Backslashes on Windows for File Paths**
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
**Examples:**
- ❌ WRONG: `D:/repos/project/file.tsx`
- ✅ CORRECT: `D:\repos\project\file.tsx`
This applies to:
- Edit tool file_path parameter
- Write tool file_path parameter
- All file operations on Windows systems
### Documentation Guidelines
**NEVER create new documentation files unless explicitly requested by the user.**
- **Priority**: Update existing README.md files rather than creating new documentation
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
- **User preference**: Only create additional .md files when user specifically asks for documentation
---
## Variable Handling
### Pattern: Safe Variable Expansion
```bash
# ✓ GOOD: Always quote variables
echo "$variable"
cp "$source" "$destination"
rm -rf "$directory"
# ✗ BAD: Unquoted variables
echo $variable # Word splitting and globbing
cp $source $destination # Breaks with spaces
rm -rf $directory # VERY DANGEROUS unquoted
```
**Why:** Unquoted variables undergo word splitting and pathname expansion, leading to unexpected behavior.
### Pattern: Default Values
```bash
# ✓ GOOD: Use parameter expansion for defaults
timeout="${TIMEOUT:-30}"
config="${CONFIG_FILE:-$HOME/.config/app.conf}"
# ✗ BAD: Manual check
if [ -z "$TIMEOUT" ]; then
timeout=30
else
timeout="$TIMEOUT"
fi
```
**Why:** Parameter expansion is concise, readable, and handles edge cases correctly.
### Anti-Pattern: Confusing Assignment and Comparison
```bash
# ✗ VERY BAD: Using = instead of ==
if [ "$var" = "value" ]; then # Assignment in POSIX test!
echo "Match"
fi
# ✓ GOOD: Use == or = correctly
if [[ "$var" == "value" ]]; then # Comparison in bash
echo "Match"
fi
# ✓ GOOD: POSIX-compliant
if [ "$var" = "value" ]; then # Single = is correct in [ ]
echo "Match"
fi
```
**Why:** In `[[ ]]`, both `=` and `==` work. In `[ ]`, only `=` is POSIX-compliant.
### Anti-Pattern: Unset Variable Access
```bash
# ✗ BAD: Accessing undefined variables
echo "Value: $undefined_variable" # Silent error, prints "Value: "
# ✓ GOOD: Use set -u
set -u
echo "Value: $undefined_variable" # Error: undefined_variable: unbound variable
# ✓ GOOD: Provide default
echo "Value: ${undefined_variable:-default}"
```
**Why:** `set -u` catches typos and logic errors early.
---
## Command Execution
### Pattern: Check Command Existence
```bash
# ✓ GOOD: Use command -v
if command -v jq &> /dev/null; then
echo "jq is installed"
else
echo "jq is not installed" >&2
exit 1
fi
# ✗ BAD: Using which
if which jq; then # Deprecated, not POSIX
echo "jq is installed"
fi
# ✗ BAD: Using type
if type jq; then # Verbose output
echo "jq is installed"
fi
```
**Why:** `command -v` is POSIX-compliant, silent, and reliable.
### Pattern: Command Substitution
```bash
# ✓ GOOD: Modern syntax with $()
result=$(command arg1 arg2)
timestamp=$(date +%s)
# ✗ BAD: Backticks (hard to nest)
result=`command arg1 arg2`
timestamp=`date +%s`
# ✓ GOOD: Nested substitution
result=$(echo "Outer: $(echo "Inner")")
# ✗ BAD: Nested backticks (requires escaping)
result=`echo "Outer: \`echo \"Inner\"\`"`
```
**Why:** `$()` is easier to read, nest, and maintain.
### Anti-Pattern: Useless Use of Cat
```bash
# ✗ BAD: UUOC (Useless Use of Cat)
cat file.txt | grep "pattern"
# ✓ GOOD: Direct input
grep "pattern" file.txt
# ✗ BAD: Multiple cats
cat file1 | grep pattern | cat | sort | cat
# ✓ GOOD: Direct pipeline
grep pattern file1 | sort
```
**Why:** Unnecessary `cat` wastes resources and adds extra processes.
### Anti-Pattern: Using ls in Scripts
```bash
# ✗ BAD: Parsing ls output
for file in $(ls *.txt); do
echo "$file"
done
# ✓ GOOD: Use globbing
for file in *.txt; do
[[ -f "$file" ]] || continue # Skip if no matches
echo "$file"
done
# ✗ BAD: Counting files with ls
count=$(ls -1 | wc -l)
# ✓ GOOD: Use array
files=(*)
count=${#files[@]}
```
**Why:** `ls` output is meant for humans, not scripts. Parsing it breaks with spaces, newlines, etc.
---
## File Operations
### Pattern: Safe File Reading
```bash
# ✓ GOOD: Preserve leading/trailing whitespace and backslashes
while IFS= read -r line; do
echo "Line: $line"
done < file.txt
# ✗ BAD: Without IFS= (strips leading/trailing whitespace)
while read -r line; do
echo "Line: $line"
done < file.txt
# ✗ BAD: Without -r (interprets backslashes)
while IFS= read line; do
echo "Line: $line"
done < file.txt
```
**Why:** `IFS=` prevents trimming, `-r` prevents backslash interpretation.
### Pattern: Null-Delimited Files
```bash
# ✓ GOOD: For filenames with special characters
find . -name "*.txt" -print0 | while IFS= read -r -d '' file; do
echo "Processing: $file"
done
# Or with mapfile (bash 4+)
mapfile -d '' -t files < <(find . -name "*.txt" -print0)
for file in "${files[@]}"; do
echo "Processing: $file"
done
# ✗ BAD: Newline-delimited (breaks with newlines in filenames)
find . -name "*.txt" | while IFS= read -r file; do
echo "Processing: $file"
done
```
**Why:** Filenames can contain any character except null and slash.
### Anti-Pattern: Testing File Existence Incorrectly
```bash
# ✗ BAD: Using ls to test existence
if ls file.txt &> /dev/null; then
echo "File exists"
fi
# ✓ GOOD: Use test operators
if [[ -f file.txt ]]; then
echo "File exists"
fi
# ✓ GOOD: Different tests
[[ -e path ]] # Exists (file or directory)
[[ -f file ]] # Regular file
[[ -d dir ]] # Directory
[[ -L link ]] # Symbolic link
[[ -r file ]] # Readable
[[ -w file ]] # Writable
[[ -x file ]] # Executable
```
**Why:** Test operators are the correct, efficient way to check file properties.
### Pattern: Temporary Files
```bash
# ✓ GOOD: Secure temporary file
temp_file=$(mktemp)
trap 'rm -f "$temp_file"' EXIT
# Use temp file
echo "data" > "$temp_file"
# ✗ BAD: Insecure temp file
temp_file="/tmp/myapp.$$"
echo "data" > "$temp_file"
# No cleanup!
# ✓ GOOD: Temporary directory
temp_dir=$(mktemp -d)
trap 'rm -rf "$temp_dir"' EXIT
```
**Why:** `mktemp` creates secure, unique files and prevents race conditions.
---
## String Processing
### Pattern: String Manipulation with Parameter Expansion
```bash
# ✓ GOOD: Use bash parameter expansion
filename="document.tar.gz"
basename="${filename%%.*}" # document
extension="${filename##*.}" # gz
name="${filename%.gz}" # document.tar
# ✗ BAD: Using external commands
basename=$(echo "$filename" | sed 's/\..*$//')
extension=$(echo "$filename" | awk -F. '{print $NF}')
```
**Why:** Parameter expansion is faster and doesn't spawn processes.
### Pattern: String Comparison
```bash
# ✓ GOOD: Use [[ ]] for strings
if [[ "$string1" == "$string2" ]]; then
echo "Equal"
fi
# ✓ GOOD: Pattern matching
if [[ "$filename" == *.txt ]]; then
echo "Text file"
fi
# ✓ GOOD: Regex matching
if [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Valid email"
fi
# ✗ BAD: Using grep for simple string check
if echo "$string" | grep -q "substring"; then
echo "Found"
fi
# ✓ GOOD: Use substring matching
if [[ "$string" == *"substring"* ]]; then
echo "Found"
fi
```
**Why:** `[[ ]]` is bash-native, faster, and more readable.
### Anti-Pattern: Word Splitting Issues
```bash
# ✗ BAD: Unquoted expansion with spaces
var="file1.txt file2.txt"
for file in $var; do # Splits on spaces!
echo "$file" # file1.txt, then file2.txt
done
# ✓ GOOD: Use array
files=("file1.txt" "file2.txt")
for file in "${files[@]}"; do
echo "$file"
done
# ✗ BAD: Word splitting in command arguments
file="my file.txt"
rm $file # Tries to remove "my" and "file.txt"!
# ✓ GOOD: Quote variables
rm "$file"
```
**Why:** Word splitting on spaces is a major source of bugs.
---
## Arrays and Loops
### Pattern: Array Declaration and Use
```bash
# ✓ GOOD: Array declaration
files=("file1.txt" "file2.txt" "file 3.txt")
# ✓ GOOD: Array expansion (each element quoted)
for file in "${files[@]}"; do
echo "$file"
done
# ✗ BAD: Unquoted array expansion
for file in ${files[@]}; do # Word splitting!
echo "$file"
done
# ✓ GOOD: Add to array
files+=("file4.txt")
# ✓ GOOD: Array length
echo "Count: ${#files[@]}"
# ✓ GOOD: Array indices
for i in "${!files[@]}"; do
echo "File $i: ${files[$i]}"
done
```
**Why:** Proper array handling prevents word splitting and globbing issues.
### Pattern: Reading Command Output into Array
```bash
# ✓ GOOD: mapfile/readarray (bash 4+)
mapfile -t lines < file.txt
# ✓ GOOD: With command substitution
mapfile -t files < <(find . -name "*.txt")
# ✗ BAD: Word splitting
files=($(find . -name "*.txt")) # Breaks with spaces in filenames!
# ✓ GOOD: Alternative (POSIX-compatible)
while IFS= read -r file; do
files+=("$file")
done < <(find . -name "*.txt")
```
**Why:** `mapfile` is efficient and handles special characters correctly.
### Anti-Pattern: C-Style For Loops for Arrays
```bash
# ✗ BAD: C-style loop for arrays
for ((i=0; i<${#files[@]}; i++)); do
echo "${files[$i]}"
done
# ✓ GOOD: For-in loop
for file in "${files[@]}"; do
echo "$file"
done
# ✓ ACCEPTABLE: When you need the index
for i in "${!files[@]}"; do
echo "Index $i: ${files[$i]}"
done
```
**Why:** For-in loops are simpler and less error-prone.
### Pattern: Loop over Range
```bash
# ✓ GOOD: Brace expansion
for i in {1..10}; do
echo "$i"
done
# ✓ GOOD: With variables (bash 4+)
start=1
end=10
for i in $(seq $start $end); do
echo "$i"
done
# ✓ GOOD: C-style (arithmetic)
for ((i=1; i<=10; i++)); do
echo "$i"
done
# ✗ BAD: Using seq in a loop unnecessarily
for i in $(seq 1 1000000); do # Creates huge string in memory!
echo "$i"
done
# ✓ GOOD: Use C-style for large ranges
for ((i=1; i<=1000000; i++)); do
echo "$i"
done
```
**Why:** Choose the right loop construct based on the use case.
---
## Conditionals and Tests
### Pattern: File Tests
```bash
# ✓ GOOD: Use appropriate test
if [[ -f "$file" ]]; then # Regular file
if [[ -d "$dir" ]]; then # Directory
if [[ -e "$path" ]]; then # Exists (any type)
if [[ -L "$link" ]]; then # Symbolic link
if [[ -r "$file" ]]; then # Readable
if [[ -w "$file" ]]; then # Writable
if [[ -x "$file" ]]; then # Executable
if [[ -s "$file" ]]; then # Non-empty file
# ✗ BAD: Incorrect test
if [[ -e "$file" ]]; then # Exists, but could be directory!
cat "$file" # Fails if directory
fi
# ✓ GOOD: Specific test
if [[ -f "$file" ]]; then
cat "$file"
fi
```
**Why:** Use the most specific test for your use case.
### Pattern: Numeric Comparison
```bash
# ✓ GOOD: Arithmetic context
if (( num > 10 )); then
echo "Greater than 10"
fi
# ✓ GOOD: Test operator
if [[ $num -gt 10 ]]; then
echo "Greater than 10"
fi
# ✗ BAD: String comparison for numbers
if [[ "$num" > "10" ]]; then # Lexicographic comparison!
echo "Greater than 10" # "9" > "10" is true!
fi
```
**Why:** Use numeric comparison operators for numbers.
### Anti-Pattern: Testing Boolean Strings
```bash
# ✗ BAD: Comparing to string "true"
if [[ "$flag" == "true" ]]; then
do_something
fi
# ✓ GOOD: Use boolean variable directly
flag=false # or true
if $flag; then
do_something
fi
# ✓ BETTER: Use integers for flags
flag=0 # false
flag=1 # true
if (( flag )); then
do_something
fi
# ✓ GOOD: For command success/failure
if command; then
echo "Success"
fi
```
**Why:** Boolean strings are error-prone; use actual booleans or return codes.
### Pattern: Multiple Conditions
```bash
# ✓ GOOD: Logical operators
if [[ condition1 && condition2 ]]; then
echo "Both true"
fi
if [[ condition1 || condition2 ]]; then
echo "At least one true"
fi
if [[ ! condition ]]; then
echo "False"
fi
# ✗ BAD: Separate tests
if [ condition1 -a condition2 ]; then # Deprecated
echo "Both true"
fi
# ✗ BAD: Nested ifs for AND
if [[ condition1 ]]; then
if [[ condition2 ]]; then
echo "Both true"
fi
fi
```
**Why:** `&&` and `||` in `[[ ]]` are clearer and recommended.
---
## Functions
### Pattern: Function Return Values
```bash
# ✓ GOOD: Return status, output to stdout
get_value() {
local value="result"
if [[ -n "$value" ]]; then
echo "$value"
return 0
else
return 1
fi
}
# Usage
if result=$(get_value); then
echo "Got: $result"
else
echo "Failed"
fi
# ✗ BAD: Using return for data
get_value() {
return 42 # Can only return 0-255!
}
result=$? # Gets 42, but limited range
```
**Why:** `return` is for exit status (0-255), not data. Output to stdout for data.
### Pattern: Local Variables in Functions
```bash
# ✓ GOOD: Declare local variables
my_function() {
local arg="$1"
local result=""
result=$(process "$arg")
echo "$result"
}
# ✗ BAD: Global variables
my_function() {
arg="$1" # Pollutes global namespace!
result="" # Global variable!
result=$(process "$arg")
echo "$result"
}
```
**Why:** Local variables prevent unexpected side effects.
### Anti-Pattern: Capturing Local Command Failure
```bash
# ✗ BAD: Local declaration masks command failure
my_function() {
local result=$(command_that_fails) # $? is from 'local', not 'command'!
echo "$result"
}
# ✓ GOOD: Separate declaration and assignment
my_function() {
local result
result=$(command_that_fails) || return 1
echo "$result"
}
# ✓ GOOD: Check command separately
my_function() {
local result
if ! result=$(command_that_fails); then
return 1
fi
echo "$result"
}
```
**Why:** Combining `local` and command substitution hides command failure.
---
## Error Handling
### Pattern: Check Command Success
```bash
# ✓ GOOD: Direct check
if ! command; then
echo "Command failed" >&2
exit 1
fi
# ✓ GOOD: With logical operator
command || {
echo "Command failed" >&2
exit 1
}
# ✓ GOOD: Capture output and check
if ! output=$(command 2>&1); then
echo "Command failed: $output" >&2
exit 1
fi
# ✗ BAD: Not checking status
command # What if it fails?
next_command
```
**Why:** Always check if commands succeed unless failure is acceptable.
### Pattern: Error Messages to stderr
```bash
# ✓ GOOD: Errors to stderr
echo "Error: Invalid argument" >&2
# ✗ BAD: Errors to stdout
echo "Error: Invalid argument"
# ✓ GOOD: Error function
error() {
echo "ERROR: $*" >&2
}
error "Something went wrong"
```
**Why:** stderr is for errors, stdout is for data output.
### Pattern: Cleanup on Exit
```bash
# ✓ GOOD: Trap for cleanup
temp_file=$(mktemp)
cleanup() {
rm -f "$temp_file"
}
trap cleanup EXIT
# Do work with temp_file
# ✗ BAD: Manual cleanup (might not run)
temp_file=$(mktemp)
# Do work
rm -f "$temp_file" # Doesn't run if script exits early!
```
**Why:** Trap ensures cleanup runs on exit, even on errors.
### Anti-Pattern: Silencing Errors
```bash
# ✗ BAD: Silencing errors
command 2>/dev/null # What if it fails?
next_command
# ✓ GOOD: Check status even if silencing output
if ! command 2>/dev/null; then
echo "Command failed" >&2
exit 1
fi
# ✓ ACCEPTABLE: When failure is expected and acceptable
if command 2>/dev/null; then
echo "Command succeeded"
else
echo "Command failed (expected)"
fi
```
**Why:** Silencing errors without checking status leads to silent failures.
---
## Process Management
### Pattern: Background Jobs
```bash
# ✓ GOOD: Track background jobs
long_running_task &
pid=$!
# Wait for completion
if wait "$pid"; then
echo "Task completed successfully"
else
echo "Task failed" >&2
fi
# ✓ GOOD: Multiple background jobs
job1 &
pid1=$!
job2 &
pid2=$!
wait "$pid1" "$pid2"
```
**Why:** Proper job management prevents zombie processes.
### Pattern: Timeout for Commands
```bash
# ✓ GOOD: Use timeout command (if available)
if timeout 30 long_running_command; then
echo "Completed within timeout"
else
echo "Timed out or failed" >&2
fi
# ✓ GOOD: Manual timeout implementation
timeout_command() {
local timeout=$1
shift
"$@" &
local pid=$!
( sleep "$timeout"; kill "$pid" 2>/dev/null ) &
local killer=$!
if wait "$pid" 2>/dev/null; then
kill "$killer" 2>/dev/null
wait "$killer" 2>/dev/null
return 0
else
return 1
fi
}
timeout_command 30 long_running_command
```
**Why:** Prevents scripts from hanging indefinitely.
### Anti-Pattern: Killing Processes Unsafely
```bash
# ✗ BAD: kill -9 immediately
kill -9 "$pid"
# ✓ GOOD: Graceful shutdown first
kill -TERM "$pid"
sleep 2
if kill -0 "$pid" 2>/dev/null; then
echo "Process still running, forcing..." >&2
kill -KILL "$pid"
fi
# ✓ GOOD: With timeout
graceful_kill() {
local pid=$1
local timeout=${2:-10}
kill -TERM "$pid" 2>/dev/null || return 0
for ((i=0; i<timeout; i++)); do
if ! kill -0 "$pid" 2>/dev/null; then
return 0
fi
sleep 1
done
echo "Forcing kill of $pid" >&2
kill -KILL "$pid" 2>/dev/null
}
```
**Why:** SIGTERM allows graceful shutdown; SIGKILL should be last resort.
---
## Security Patterns
### Pattern: Input Validation
```bash
# ✓ GOOD: Whitelist validation
validate_action() {
local action=$1
case "$action" in
start|stop|restart|status)
return 0
;;
*)
echo "Error: Invalid action: $action" >&2
return 1
;;
esac
}
# ✗ BAD: No validation
action="$1"
systemctl "$action" myservice # User can pass arbitrary commands!
# ✓ GOOD: Validate first
if validate_action "$1"; then
systemctl "$1" myservice
else
exit 1
fi
```
**Why:** Whitelist validation prevents command injection.
### Pattern: Avoid eval
```bash
# ✗ BAD: eval with user input
eval "$user_command" # DANGEROUS!
# ✓ GOOD: Use arrays
command_args=("$arg1" "$arg2" "$arg3")
command "${command_args[@]}"
# ✗ BAD: Dynamic variable names
eval "var_$name=value"
# ✓ GOOD: Associative arrays (bash 4+)
declare -A vars
vars[$name]="value"
```
**Why:** `eval` with user input is a security vulnerability.
### Pattern: Safe PATH
```bash
# ✓ GOOD: Set explicit PATH
export PATH="/usr/local/bin:/usr/bin:/bin"
# ✓ GOOD: Use absolute paths for critical commands
/usr/bin/rm -rf "$directory"
# ✗ BAD: Trusting user's PATH
rm -rf "$directory" # What if there's a malicious 'rm' in PATH?
```
**Why:** Prevents PATH injection attacks.
---
## Summary
**Most Critical Patterns:**
1. Always quote variable expansions: `"$var"`
2. Use `set -euo pipefail` for safety
3. Prefer `[[ ]]` over `[ ]` in bash
4. Use arrays for lists: `"${array[@]}"`
5. Check command success: `if ! command; then`
6. Use local variables in functions
7. Errors to stderr: `echo "Error" >&2`
8. Use `mktemp` for temporary files
9. Cleanup with traps: `trap cleanup EXIT`
10. Validate all user input
**Most Dangerous Anti-Patterns:**
1. Unquoted variables: `$var`
2. Parsing `ls` output
3. Using `eval` with user input
4. Silencing errors without checking
5. Not using `set -u` or defaults
6. Global variables in functions
7. Word splitting on filenames
8. Testing strings with `>` for numbers
9. `kill -9` without trying graceful shutdown
10. Trusting user PATH
Following these patterns and avoiding anti-patterns will result in robust, secure, and maintainable bash scripts.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,739 @@
# Bash Scripting Resources
Comprehensive directory of authoritative sources, tools, and learning resources for bash scripting.
---
## Table of Contents
1. [Official Documentation](#official-documentation)
2. [Style Guides and Standards](#style-guides-and-standards)
3. [Tools and Utilities](#tools-and-utilities)
4. [Learning Resources](#learning-resources)
5. [Community Resources](#community-resources)
6. [Books](#books)
7. [Cheat Sheets and Quick References](#cheat-sheets-and-quick-references)
8. [Testing and Quality](#testing-and-quality)
9. [Platform-Specific Resources](#platform-specific-resources)
10. [Advanced Topics](#advanced-topics)
---
## 🚨 CRITICAL GUIDELINES
### Windows File Path Requirements
**MANDATORY: Always Use Backslashes on Windows for File Paths**
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
**Examples:**
- ❌ WRONG: `D:/repos/project/file.tsx`
- ✅ CORRECT: `D:\repos\project\file.tsx`
This applies to:
- Edit tool file_path parameter
- Write tool file_path parameter
- All file operations on Windows systems
### Documentation Guidelines
**NEVER create new documentation files unless explicitly requested by the user.**
- **Priority**: Update existing README.md files rather than creating new documentation
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
- **User preference**: Only create additional .md files when user specifically asks for documentation
---
## Official Documentation
### Bash Manual
**GNU Bash Reference Manual**
- **URL:** https://www.gnu.org/software/bash/manual/
- **Description:** The authoritative reference for bash features, syntax, and built-ins
- **Use for:** Detailed feature documentation, syntax clarification, version-specific features
**Bash Man Page**
```bash
man bash # Complete bash documentation
man bash-builtins # Built-in commands
```
- **Use for:** Quick reference on local system, offline documentation
### POSIX Standards
**POSIX Shell Command Language**
- **URL:** https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
- **Description:** IEEE/Open Group specification for portable shell scripting
- **Use for:** Writing portable scripts, understanding sh vs bash differences
**POSIX Utilities**
- **URL:** https://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html
- **Description:** Standard utilities available in POSIX-compliant systems
- **Use for:** Portable command usage, cross-platform compatibility
### Command Documentation
**GNU Coreutils Manual**
- **URL:** https://www.gnu.org/software/coreutils/manual/
- **Description:** Documentation for core GNU utilities (ls, cat, grep, etc.)
- **Use for:** Understanding Linux command behavior, GNU-specific features
**Man Pages Online**
- **URL:** https://man7.org/linux/man-pages/
- **URL:** https://www.freebsd.org/cgi/man.cgi (BSD/macOS)
- **Description:** Online searchable man pages
- **Use for:** Quick online reference, comparing Linux vs BSD commands
---
## Style Guides and Standards
### Google Shell Style Guide
**URL:** https://google.github.io/styleguide/shellguide.html
**Key Points:**
- Industry-standard practices from Google
- Covers naming conventions, formatting, best practices
- When to use shell vs other languages
- Safety and portability guidelines
**Use for:** Professional code style, team standards, code reviews
### Defensive Bash Programming
**URL:** https://kfirlavi.herokuapp.com/blog/2012/11/14/defensive-bash-programming
**Key Points:**
- Writing robust bash scripts
- Error handling patterns
- Safe coding practices
- Code organization
**Use for:** Improving script reliability, avoiding common pitfalls
### Shell Style Guide (GitHub)
**URL:** https://github.com/bahamas10/bash-style-guide
**Key Points:**
- Community-driven style guidelines
- Practical examples
- Modern bash features
**Use for:** Alternative perspectives on style, community standards
---
## Tools and Utilities
### ShellCheck
**Website:** https://www.shellcheck.net/
**GitHub:** https://github.com/koalaman/shellcheck
**Online Tool:** https://www.shellcheck.net/ (paste code for instant feedback)
**Description:** Static analysis tool for shell scripts
**Installation:**
```bash
# Ubuntu/Debian
apt-get install shellcheck
# macOS
brew install shellcheck
# Windows (Scoop)
scoop install shellcheck
# Via Docker
docker run --rm -v "$PWD:/mnt" koalaman/shellcheck script.sh
```
**Usage:**
```bash
shellcheck script.sh # Check script
shellcheck -x script.sh # Follow source statements
shellcheck -f json script.sh # JSON output
shellcheck -e SC2086 script.sh # Exclude specific warnings
```
**ShellCheck Wiki:** https://www.shellcheck.net/wiki/
- Detailed explanations of every warning
- **Use for:** Understanding and fixing ShellCheck warnings
### shfmt
**GitHub:** https://github.com/mvdan/sh
**Description:** Shell script formatter
**Installation:**
```bash
# macOS
brew install shfmt
# Go
go install mvdan.cc/sh/v3/cmd/shfmt@latest
```
**Usage:**
```bash
shfmt -i 4 -w script.sh # Format with 4-space indent
shfmt -d script.sh # Show diff without modifying
shfmt -l script.sh # List files that would be changed
```
**Use for:** Consistent code formatting, automated formatting in CI
### BATS (Bash Automated Testing System)
**GitHub:** https://github.com/bats-core/bats-core
**Description:** Testing framework for bash scripts
**Installation:**
```bash
git clone https://github.com/bats-core/bats-core.git
cd bats-core
./install.sh /usr/local
```
**Usage:**
```bash
bats test/ # Run all tests
bats test/script.bats # Run specific test file
bats --tap test/ # TAP output format
```
**Documentation:** https://bats-core.readthedocs.io/
**Use for:** Unit testing bash scripts, CI/CD integration
### bashate
**GitHub:** https://github.com/openstack/bashate
**Description:** Style checker (used by OpenStack)
**Installation:**
```bash
pip install bashate
```
**Usage:**
```bash
bashate script.sh
bashate -i E006 script.sh # Ignore specific errors
```
**Use for:** Additional style checking beyond ShellCheck
### checkbashisms
**Package:** devscripts (Debian)
**Description:** Checks for bashisms in sh scripts
**Installation:**
```bash
apt-get install devscripts # Ubuntu/Debian
```
**Usage:**
```bash
checkbashisms script.sh
checkbashisms -f script.sh # Force check even if #!/bin/bash
```
**Use for:** Ensuring POSIX compliance, portable scripts
---
## Learning Resources
### Interactive Tutorials
**Bash Academy**
- **URL:** https://www.bash.academy/
- **Description:** Modern, comprehensive bash tutorial
- **Topics:** Basics, scripting, advanced features
- **Use for:** Learning bash from scratch, structured learning path
**Learn Shell**
- **URL:** https://www.learnshell.org/
- **Description:** Interactive bash tutorial with exercises
- **Use for:** Hands-on practice, beginners
**Bash Scripting Tutorial**
- **URL:** https://linuxconfig.org/bash-scripting-tutorial
- **Description:** Comprehensive tutorial series
- **Use for:** Step-by-step learning, examples
### Guides and Documentation
**Bash Guide for Beginners**
- **URL:** https://tldp.org/LDP/Bash-Beginners-Guide/html/
- **Author:** The Linux Documentation Project
- **Description:** Comprehensive guide covering basics to intermediate
- **Use for:** Structured learning, reference material
**Advanced Bash-Scripting Guide**
- **URL:** https://tldp.org/LDP/abs/html/
- **Description:** In-depth coverage of advanced bash topics
- **Topics:** Complex scripting, text processing, system administration
- **Use for:** Advanced techniques, real-world examples
**Bash Hackers Wiki**
- **URL:** https://wiki.bash-hackers.org/
- **Alternative:** https://flokoe.github.io/bash-hackers-wiki/ (maintained mirror)
- **Description:** Community-driven bash documentation
- **Use for:** In-depth explanations, advanced topics, edge cases
**Greg's Wiki (Wooledge)**
- **URL:** https://mywiki.wooledge.org/
- **Key Pages:**
- https://mywiki.wooledge.org/BashFAQ
- https://mywiki.wooledge.org/BashPitfalls
- https://mywiki.wooledge.org/BashGuide
- **Description:** High-quality bash Q&A and guides
- **Use for:** Common questions, avoiding pitfalls, best practices
### Video Courses
**Bash Scripting on Linux (Udemy)**
- **Description:** Comprehensive video course
- **Use for:** Visual learners
**Shell Scripting: Discover How to Automate Command Line Tasks (Udemy)**
- **Description:** Practical shell scripting course
- **Use for:** Automation-focused learning
**LinkedIn Learning - Learning Bash Scripting**
- **Description:** Professional development course
- **Use for:** Structured corporate training
---
## Community Resources
### Stack Overflow
**Bash Tag**
- **URL:** https://stackoverflow.com/questions/tagged/bash
- **Use for:** Specific problems, code review, troubleshooting
**Top Questions:**
- **URL:** https://stackoverflow.com/questions/tagged/bash?tab=Votes
- **Use for:** Common problems and solutions
### Unix & Linux Stack Exchange
**URL:** https://unix.stackexchange.com/
**Shell Tag:** https://unix.stackexchange.com/questions/tagged/shell
**Bash Tag:** https://unix.stackexchange.com/questions/tagged/bash
**Use for:** Unix/Linux-specific questions, system administration
### Reddit
**/r/bash**
- **URL:** https://www.reddit.com/r/bash/
- **Description:** Bash scripting community
- **Use for:** Discussions, learning resources, help
**/r/commandline**
- **URL:** https://www.reddit.com/r/commandline/
- **Description:** Command-line interface community
- **Use for:** CLI tips, tools, productivity
### IRC/Chat
**Freenode #bash**
- **URL:** irc://irc.freenode.net/bash
- **Description:** Real-time bash help channel
- **Use for:** Live help, quick questions
**Libera.Chat #bash**
- **URL:** irc://irc.libera.chat/bash
- **Description:** Alternative IRC channel
- **Use for:** Live community support
---
## Books
### "Classic Shell Scripting" by Arnold Robbins & Nelson Beebe
**Publisher:** O'Reilly
**ISBN:** 978-0596005955
**Topics:**
- Shell basics and portability
- Text processing and filters
- Shell programming patterns
**Use for:** Comprehensive reference, professional development
### "Learning the bash Shell" by Cameron Newham
**Publisher:** O'Reilly
**ISBN:** 978-0596009656
**Topics:**
- Bash basics
- Command-line editing
- Shell programming
**Use for:** Systematic learning, reference
### "Bash Cookbook" by Carl Albing & JP Vossen
**Publisher:** O'Reilly
**ISBN:** 978-1491975336
**Topics:**
- Solutions to common problems
- Recipes and patterns
- Real-world examples
**Use for:** Problem-solving, practical examples
### "Wicked Cool Shell Scripts" by Dave Taylor & Brandon Perry
**Publisher:** No Starch Press
**ISBN:** 978-1593276027
**Topics:**
- Creative shell scripting
- System administration
- Fun and practical scripts
**Use for:** Inspiration, practical applications
### "The Linux Command Line" by William Shotts
**Publisher:** No Starch Press
**ISBN:** 978-1593279523
**Free PDF:** https://linuxcommand.org/tlcl.php
**Topics:**
- Command-line basics
- Shell scripting fundamentals
- Linux system administration
**Use for:** Beginners, comprehensive introduction
---
## Cheat Sheets and Quick References
### Bash Cheat Sheet (DevHints)
**URL:** https://devhints.io/bash
**Content:**
- Quick syntax reference
- Common patterns
- Parameter expansion
- Conditionals and loops
**Use for:** Quick lookups, syntax reminders
### Bash Scripting Cheat Sheet (GitHub)
**URL:** https://github.com/LeCoupa/awesome-cheatsheets/blob/master/languages/bash.sh
**Content:**
- Comprehensive syntax guide
- Examples and explanations
- Best practices
**Use for:** Single-file reference
### explainshell.com
**URL:** https://explainshell.com/
**Description:** Interactive tool that explains shell commands
**Example:** Paste `tar -xzvf file.tar.gz` to get detailed explanation of each flag
**Use for:** Understanding complex commands, learning command options
### Command Line Fu
**URL:** https://www.commandlinefu.com/
**Description:** Community-contributed command-line snippets
**Use for:** One-liners, clever solutions, learning new commands
### tldr Pages
**URL:** https://tldr.sh/
**GitHub:** https://github.com/tldr-pages/tldr
**Description:** Simplified man pages with examples
**Installation:**
```bash
npm install -g tldr
# Or
brew install tldr
```
**Usage:**
```bash
tldr tar
tldr grep
tldr find
```
**Use for:** Quick command examples, practical usage
---
## Testing and Quality
### Testing Frameworks
**BATS (Bash Automated Testing System)**
- **URL:** https://github.com/bats-core/bats-core
- **Documentation:** https://bats-core.readthedocs.io/
- **Use for:** Unit testing
**shUnit2**
- **URL:** https://github.com/kward/shunit2
- **Description:** xUnit-based unit testing framework
- **Use for:** Alternative to BATS
**Bash Unit**
- **URL:** https://github.com/pgrange/bash_unit
- **Description:** Bash unit testing
- **Use for:** Lightweight testing
### CI/CD Integration
**GitHub Actions Example**
```yaml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install ShellCheck
run: sudo apt-get install -y shellcheck
- name: Run ShellCheck
run: find . -name "*.sh" -exec shellcheck {} +
- name: Install BATS
run: |
git clone https://github.com/bats-core/bats-core.git
cd bats-core
sudo ./install.sh /usr/local
- name: Run Tests
run: bats test/
```
**GitLab CI Example**
```yaml
test:
image: koalaman/shellcheck-alpine
script:
- find . -name "*.sh" -exec shellcheck {} +
bats:
image: bats/bats
script:
- bats test/
```
### Code Coverage
**bashcov**
- **URL:** https://github.com/infertux/bashcov
- **Description:** Code coverage for bash
- **Installation:** `gem install bashcov`
- **Use for:** Measuring test coverage
---
## Platform-Specific Resources
### Linux
**Linux Man Pages**
- **URL:** https://man7.org/linux/man-pages/
- **Use for:** Linux-specific command documentation
**systemd Documentation**
- **URL:** https://www.freedesktop.org/software/systemd/man/
- **Use for:** systemd service management
### macOS
**macOS Man Pages**
- **URL:** https://www.freebsd.org/cgi/man.cgi
- **Description:** BSD-based commands (similar to macOS)
- **Use for:** macOS command differences
**Homebrew**
- **URL:** https://brew.sh/
- **Use for:** Installing GNU tools on macOS
### Windows
**Git for Windows**
- **URL:** https://gitforwindows.org/
- **Documentation:** https://github.com/git-for-windows/git/wiki
- **Use for:** Git Bash on Windows
**WSL Documentation**
- **URL:** https://docs.microsoft.com/en-us/windows/wsl/
- **Use for:** Windows Subsystem for Linux
**Cygwin**
- **URL:** https://www.cygwin.com/
- **Use for:** POSIX environment on Windows
### Containers
**Docker Bash Best Practices**
- **URL:** https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
- **Use for:** Bash in containers
**Container Best Practices**
- **URL:** https://cloud.google.com/architecture/best-practices-for-building-containers
- **Use for:** Production container scripts
---
## Advanced Topics
### Process Substitution
**Greg's Wiki:**
- **URL:** https://mywiki.wooledge.org/ProcessSubstitution
- **Use for:** Understanding `<()` syntax
### Parameter Expansion
**Bash Hackers Wiki:**
- **URL:** https://wiki.bash-hackers.org/syntax/pe
- **Use for:** Complete parameter expansion reference
### Regular Expressions
**Bash Regex:**
- **URL:** https://mywiki.wooledge.org/RegularExpression
- **Use for:** Regex in bash `[[ =~ ]]`
**PCRE vs POSIX:**
- **URL:** https://www.regular-expressions.info/posix.html
- **Use for:** Understanding regex flavors
### Parallel Processing
**GNU Parallel:**
- **URL:** https://www.gnu.org/software/parallel/
- **Tutorial:** https://www.gnu.org/software/parallel/parallel_tutorial.html
- **Use for:** Parallel command execution
### Job Control
**Bash Job Control:**
- **URL:** https://www.gnu.org/software/bash/manual/html_node/Job-Control.html
- **Use for:** Background jobs, job management
---
## Troubleshooting Resources
### Debugging Tools
**bashdb**
- **URL:** http://bashdb.sourceforge.net/
- **Description:** Bash debugger
- **Use for:** Step-by-step debugging
**xtrace**
```bash
set -x # Enable
set +x # Disable
```
- **Use for:** Trace command execution
**PS4 for Better Trace Output**
```bash
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
set -x
```
### Common Issues
**Bash Pitfalls**
- **URL:** https://mywiki.wooledge.org/BashPitfalls
- **Description:** 50+ common mistakes in bash
- **Use for:** Avoiding and fixing common errors
**Bash FAQ**
- **URL:** https://mywiki.wooledge.org/BashFAQ
- **Description:** Frequently asked questions
- **Use for:** Quick answers to common questions
---
## Summary: Where to Find Information
| Question Type | Resource |
|---------------|----------|
| Syntax reference | Bash Manual, DevHints cheat sheet |
| Best practices | Google Shell Style Guide, ShellCheck |
| Portable scripting | POSIX specification, checkbashisms |
| Quick examples | tldr, explainshell.com |
| Common mistakes | Bash Pitfalls, ShellCheck Wiki |
| Advanced topics | Bash Hackers Wiki, Greg's Wiki |
| Testing | BATS documentation |
| Platform differences | Platform-specific docs, Stack Overflow |
| Troubleshooting | Stack Overflow, Unix & Linux SE |
| Learning path | Bash Academy, TLDP guides |
---
## Quick Resource Lookup
**When writing a new script:**
1. Start with template from Google Style Guide
2. Use ShellCheck while developing
3. Reference Bash Manual for specific features
4. Check Bash Pitfalls for common mistakes
**When debugging:**
1. Use `set -x` for tracing
2. Check ShellCheck warnings
3. Search Bash Pitfalls
4. Search Stack Overflow for specific error
**When learning:**
1. Start with Bash Academy or TLDP
2. Use explainshell.com for commands
3. Read Greg's Wiki for in-depth topics
4. Practice with BATS tests
**When ensuring quality:**
1. Run ShellCheck
2. Run shellcheck
3. Format with shfmt
4. Write BATS tests
5. Review against Google Style Guide
These resources provide authoritative, up-to-date information for all aspects of bash scripting.

View File

@@ -0,0 +1,798 @@
# Windows Git Bash / MINGW Path Conversion & Shell Detection
**CRITICAL KNOWLEDGE FOR BASH SCRIPTING ON WINDOWS**
This reference provides comprehensive guidance for handling path conversion and shell detection in Git Bash/MINGW/MSYS2 environments on Windows - essential knowledge for cross-platform bash scripting.
---
## Table of Contents
1. [Path Conversion in Git Bash/MINGW](#path-conversion-in-git-bashMINGW)
2. [Shell Detection Methods](#shell-detection-methods)
3. [Claude Code Specific Issues](#claude-code-specific-issues)
4. [Practical Solutions](#practical-solutions)
5. [Best Practices](#best-practices)
---
## Path Conversion in Git Bash/MINGW
### Automatic Conversion Behavior
Git Bash/MINGW automatically converts Unix-style paths to Windows paths when passing arguments to native Windows programs. Understanding this behavior is critical for writing portable scripts.
**Conversion Rules:**
```bash
# Unix → Windows path conversion
/foo → C:/Program Files/Git/usr/foo
# Path lists (colon-separated → semicolon-separated)
/foo:/bar → C:\msys64\foo;C:\msys64\bar
# Arguments with paths
--dir=/foo → --dir=C:/msys64/foo
```
### What Triggers Conversion
Automatic path conversion is triggered by:
```bash
# ✓ Leading forward slash (/) in arguments
command /c/Users/username/file.txt
# ✓ Colon-separated path lists
export PATH=/usr/bin:/usr/local/bin
# ✓ Arguments after - or , with path components
command --path=/tmp/data
```
### What's Exempt from Conversion
These patterns do NOT trigger automatic conversion:
```bash
# ✓ Arguments containing = (variable assignments)
VAR=/path/to/something
# ✓ Drive specifiers (C:)
C:/Windows/System32
# ✓ Arguments with ; (already Windows format)
PATH=C:\foo;C:\bar
# ✓ Arguments starting with // (Windows switches or UNC paths)
//server/share
command //e //s # Command-line switches
```
### Control Environment Variables
**MSYS_NO_PATHCONV** (Git for Windows only):
```bash
# Disable ALL path conversion
export MSYS_NO_PATHCONV=1
command /path/to/file
# Per-command usage (recommended)
MSYS_NO_PATHCONV=1 command /path/to/file
# Value doesn't matter, just needs to be defined
MSYS_NO_PATHCONV=0 # Still disables conversion
```
**MSYS2_ARG_CONV_EXCL** (MSYS2 only):
```bash
# Exclude everything
export MSYS2_ARG_CONV_EXCL="*"
# Exclude specific prefixes
export MSYS2_ARG_CONV_EXCL="--dir=;/test"
# Multiple patterns (semicolon-separated)
export MSYS2_ARG_CONV_EXCL="--path=;--config=;/tmp"
```
**MSYS2_ENV_CONV_EXCL**:
```bash
# Prevents environment variable conversion
# Same syntax as MSYS2_ARG_CONV_EXCL
export MSYS2_ENV_CONV_EXCL="MY_PATH;CONFIG_DIR"
```
### Manual Conversion with cygpath
The `cygpath` utility provides precise control over path conversion:
```bash
# Convert Windows → Unix format
unix_path=$(cygpath -u "C:\Users\username\file.txt")
# Result: /c/Users/username/file.txt
# Convert Unix → Windows format
windows_path=$(cygpath -w "/c/Users/username/file.txt")
# Result: C:\Users\username\file.txt
# Convert to mixed format (forward slashes, Windows drive)
mixed_path=$(cygpath -m "/c/Users/username/file.txt")
# Result: C:/Users/username/file.txt
# Convert absolute path
absolute_path=$(cygpath -a "relative/path")
# Convert multiple paths
cygpath -u "C:\path1" "C:\path2"
```
**Practical cygpath usage:**
```bash
#!/usr/bin/env bash
# Cross-platform path handling
get_native_path() {
local path="$1"
# Check if running on Windows (Git Bash/MINGW)
if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "mingw"* ]]; then
# Convert to Windows format for native programs
cygpath -w "$path"
else
# Already Unix format on Linux/macOS
echo "$path"
fi
}
# Usage
native_path=$(get_native_path "/c/Users/data")
windows_program.exe "$native_path"
```
### Common Workarounds
When automatic conversion causes issues:
**1. Use double slashes:**
```bash
# Problem: /e gets converted to C:/Program Files/Git/e
command /e /s
# Solution: Use double slashes
command //e //s # Treated as switches, not paths
```
**2. Use dash notation:**
```bash
# Problem: /e flag converted to path
command /e /s
# Solution: Use dash notation
command -e -s
```
**3. Set MSYS_NO_PATHCONV temporarily:**
```bash
# Disable conversion for single command
MSYS_NO_PATHCONV=1 command /path/with/special/chars
# Or export for script section
export MSYS_NO_PATHCONV=1
command1 /path1
command2 /path2
unset MSYS_NO_PATHCONV
```
**4. Quote paths with spaces:**
```bash
# Always quote paths with spaces
command "/c/Program Files/App/file.txt"
# Or escape spaces
command /c/Program\ Files/App/file.txt
```
---
## Shell Detection Methods
### Method 1: $OSTYPE (Fastest, Bash-Only)
Best for: Quick platform detection in bash scripts
```bash
#!/usr/bin/env bash
case "$OSTYPE" in
linux-gnu*)
echo "Linux"
;;
darwin*)
echo "macOS"
;;
cygwin*)
echo "Cygwin"
;;
msys*)
echo "MSYS/Git Bash/MinGW"
# Most common in Git for Windows
;;
win*)
echo "Windows (native)"
;;
*)
echo "Unknown: $OSTYPE"
;;
esac
```
**Advantages:**
- Fast (shell variable, no external command)
- Reliable for bash
- No forking required
**Disadvantages:**
- Bash-specific (not available in POSIX sh)
- Less detailed than uname
### Method 2: uname -s (Most Portable)
Best for: Maximum portability and detailed information
```bash
#!/bin/sh
# Works in any POSIX shell
case "$(uname -s)" in
Darwin*)
echo "macOS"
;;
Linux*)
# Check for WSL
if grep -qi microsoft /proc/version 2>/dev/null; then
echo "Windows Subsystem for Linux (WSL)"
else
echo "Linux (native)"
fi
;;
CYGWIN*)
echo "Cygwin"
;;
MINGW64*)
echo "Git Bash 64-bit / MINGW64"
;;
MINGW32*)
echo "Git Bash 32-bit / MINGW32"
;;
MSYS_NT*)
echo "MSYS"
;;
*)
echo "Unknown: $(uname -s)"
;;
esac
```
**Common uname -s outputs:**
| Output | Platform | Description |
|--------|----------|-------------|
| `Darwin` | macOS | All macOS versions |
| `Linux` | Linux/WSL | Check `/proc/version` for WSL |
| `MINGW64_NT-10.0-*` | Git Bash | Git for Windows (64-bit) |
| `MINGW32_NT-10.0-*` | Git Bash | Git for Windows (32-bit) |
| `CYGWIN_NT-*` | Cygwin | Cygwin environment |
| `MSYS_NT-*` | MSYS | MSYS environment |
**Advantages:**
- Works in any POSIX shell
- Detailed system information
- Standard on all Unix-like systems
**Disadvantages:**
- Requires forking (slower than $OSTYPE)
- Output format varies by OS version
### Method 3: $MSYSTEM (MSYS2/Git Bash Specific)
Best for: Detecting MINGW subsystem type
```bash
#!/usr/bin/env bash
case "$MSYSTEM" in
MINGW64)
echo "Native Windows 64-bit environment"
# Build native Windows 64-bit applications
;;
MINGW32)
echo "Native Windows 32-bit environment"
# Build native Windows 32-bit applications
;;
MSYS)
echo "POSIX-compliant environment"
# Build POSIX applications (depend on msys-2.0.dll)
;;
"")
echo "Not running in MSYS2/Git Bash"
;;
*)
echo "Unknown MSYSTEM: $MSYSTEM"
;;
esac
```
**MSYSTEM Values:**
| Value | Purpose | Path Conversion | Libraries |
|-------|---------|-----------------|-----------|
| `MINGW64` | Native Windows 64-bit | Automatic | Windows native (mingw-w64) |
| `MINGW32` | Native Windows 32-bit | Automatic | Windows native (mingw) |
| `MSYS` | POSIX environment | Minimal | POSIX (msys-2.0.dll) |
**WARNING:** Never set `$MSYSTEM` manually outside of MSYS2/Git Bash shells! It's automatically set by the environment and changing it can break the system.
**Advantages:**
- Precise subsystem detection
- Important for build systems
- Fast (environment variable)
**Disadvantages:**
- Only available in MSYS2/Git Bash
- Not set on other platforms
### Comprehensive Detection Function
Combine all methods for robust detection:
```bash
#!/usr/bin/env bash
detect_platform() {
local platform=""
local details=""
# Check MSYSTEM first (most specific for Git Bash)
if [[ -n "${MSYSTEM:-}" ]]; then
platform="gitbash"
details="$MSYSTEM"
echo "platform=$platform subsystem=$MSYSTEM"
return 0
fi
# Check OSTYPE
case "$OSTYPE" in
linux-gnu*)
# Distinguish WSL from native Linux
if grep -qi microsoft /proc/version 2>/dev/null; then
platform="wsl"
if [[ -n "${WSL_DISTRO_NAME:-}" ]]; then
details="$WSL_DISTRO_NAME"
fi
else
platform="linux"
fi
;;
darwin*)
platform="macos"
;;
msys*|mingw*|cygwin*)
platform="gitbash"
;;
*)
# Fallback to uname
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*)
platform="gitbash"
;;
CYGWIN*)
platform="cygwin"
;;
*)
platform="unknown"
;;
esac
;;
esac
echo "platform=$platform${details:+ details=$details}"
}
# Usage
platform_info=$(detect_platform)
echo "$platform_info"
```
---
## Claude Code Specific Issues
### Issue #2602: Snapshot Path Conversion Failure
**Problem:**
```
/usr/bin/bash: line 1: C:UsersDavid...No such file
```
**Root Cause:**
- Node.js `os.tmpdir()` returns Windows paths (e.g., `C:\Users\...`)
- Git Bash expects Unix paths (e.g., `/c/Users/...`)
- Automatic conversion fails due to path format mismatch
**Solution (Claude Code v1.0.51+):**
Set environment variable before starting Claude Code:
```powershell
# PowerShell
$env:CLAUDE_CODE_GIT_BASH_PATH = "C:\Program Files\git\bin\bash.exe"
```
```cmd
# CMD
set CLAUDE_CODE_GIT_BASH_PATH=C:\Program Files\git\bin\bash.exe
```
```bash
# Git Bash (add to ~/.bashrc)
export CLAUDE_CODE_GIT_BASH_PATH="C:\\Program Files\\git\\bin\\bash.exe"
```
**Note:** Versions 1.0.72+ reportedly work without modifications, but setting the environment variable ensures compatibility.
### Other Known Issues
**Drive letter duplication:**
```bash
# Problem
cd D:\dev
pwd
# Output: D:\d\dev (incorrect)
# Solution: Use Unix-style path in Git Bash
cd /d/dev
pwd
# Output: /d/dev
```
**Spaces in paths:**
```bash
# Problem: Unquoted path with spaces
cd C:\Program Files\App # Fails
# Solution: Always quote paths with spaces
cd "C:\Program Files\App"
cd /c/Program\ Files/App
```
**VS Code extension Git Bash detection:**
VS Code may not auto-detect Git Bash. Configure manually in settings:
```json
{
"terminal.integrated.defaultProfile.windows": "Git Bash",
"terminal.integrated.profiles.windows": {
"Git Bash": {
"path": "C:\\Program Files\\Git\\bin\\bash.exe"
}
}
}
```
---
## Practical Solutions
### Cross-Platform Path Handling Function
```bash
#!/usr/bin/env bash
# Convert path to format appropriate for current platform
normalize_path_for_platform() {
local path="$1"
case "$OSTYPE" in
msys*|mingw*)
# On Git Bash, convert to Unix format if Windows format provided
if [[ "$path" =~ ^[A-Z]:\\ ]]; then
# Windows path detected, convert to Unix
path=$(cygpath -u "$path" 2>/dev/null || echo "$path")
fi
;;
*)
# On Linux/macOS, path is already correct
;;
esac
echo "$path"
}
# Convert path to native format for external programs
convert_to_native_path() {
local path="$1"
case "$OSTYPE" in
msys*|mingw*)
# Convert to Windows format for native Windows programs
cygpath -w "$path" 2>/dev/null || echo "$path"
;;
*)
# Already native on Linux/macOS
echo "$path"
;;
esac
}
# Example usage
input_path="/c/Users/username/file.txt"
normalized=$(normalize_path_for_platform "$input_path")
echo "Normalized: $normalized"
native=$(convert_to_native_path "$normalized")
echo "Native: $native"
```
### Script Template for Windows Compatibility
```bash
#!/usr/bin/env bash
set -euo pipefail
# Detect if running on Git Bash/MINGW
is_git_bash() {
[[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "mingw"* ]]
}
# Handle path conversion based on platform
get_path() {
local path="$1"
if is_git_bash; then
# Ensure Unix format in Git Bash
if [[ "$path" =~ ^[A-Z]:\\ ]]; then
cygpath -u "$path"
else
echo "$path"
fi
else
echo "$path"
fi
}
# Call Windows program from Git Bash
call_windows_program() {
local program="$1"
shift
local args=("$@")
if is_git_bash; then
# Disable path conversion for complex arguments
MSYS_NO_PATHCONV=1 "$program" "${args[@]}"
else
"$program" "${args[@]}"
fi
}
# Main script logic
main() {
local file_path="$1"
# Normalize path
file_path=$(get_path "$file_path")
# Process file
echo "Processing: $file_path"
# Call Windows program if needed
if is_git_bash; then
local native_path
native_path=$(cygpath -w "$file_path")
call_windows_program notepad.exe "$native_path"
fi
}
main "$@"
```
### Handling Command-Line Arguments
```bash
#!/usr/bin/env bash
# Parse arguments that might contain paths
parse_arguments() {
while [[ $# -gt 0 ]]; do
case "$1" in
--path=*)
local path="${1#*=}"
# Disable conversion for this specific argument pattern
MSYS2_ARG_CONV_EXCL="--path=" command --path="$path"
shift
;;
--dir)
local dir="$2"
# Use converted path
local native_dir
if command -v cygpath &>/dev/null; then
native_dir=$(cygpath -w "$dir")
else
native_dir="$dir"
fi
command --dir "$native_dir"
shift 2
;;
*)
shift
;;
esac
done
}
```
---
## Best Practices
### 1. Always Quote Paths
```bash
# ✗ WRONG - Breaks with spaces
cd $path
# ✓ CORRECT - Works with all paths
cd "$path"
```
### 2. Use cygpath for Reliable Conversion
```bash
# ✗ WRONG - Manual conversion is error-prone
path="${path//\\/\/}"
path="${path/C:/\/c}"
# ✓ CORRECT - Use cygpath
path=$(cygpath -u "$path")
```
### 3. Detect Platform Before Path Operations
```bash
# ✓ CORRECT - Platform-aware
if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "mingw"* ]]; then
# Git Bash specific handling
path=$(cygpath -u "$windows_path")
else
# Linux/macOS handling
path="$unix_path"
fi
```
### 4. Use MSYS_NO_PATHCONV Sparingly
```bash
# ✗ WRONG - Disables all conversion globally
export MSYS_NO_PATHCONV=1
# ✓ CORRECT - Per-command when needed
MSYS_NO_PATHCONV=1 command --flag=/value
```
### 5. Test on Target Platform
Always test scripts on Windows with Git Bash if that's a target platform:
```bash
# Test script
bash -n script.sh # Syntax check
shellcheck script.sh # Static analysis
bash script.sh # Run on actual platform
```
### 6. Document Platform Requirements
```bash
#!/usr/bin/env bash
#
# Platform Support:
# - Linux: Full support
# - macOS: Full support
# - Windows Git Bash: Requires Git for Windows 2.x+
# - Windows WSL: Full support
#
# Known Issues:
# - Path conversion may occur when calling Windows programs from Git Bash
# - Use MSYS_NO_PATHCONV=1 if experiencing path-related errors
```
### 7. Use Forward Slashes in Git Bash
```bash
# ✓ PREFERRED - Works in all environments
cd /c/Users/username/project
# ✗ AVOID - Requires escaping or quoting
cd "C:\Users\username\project"
cd C:\\Users\\username\\project
```
### 8. Check for cygpath Availability
```bash
# Graceful fallback if cygpath not available
convert_path() {
local path="$1"
if command -v cygpath &>/dev/null; then
cygpath -u "$path"
else
# Manual conversion as fallback
echo "$path" | sed 's|\\|/|g' | sed 's|^\([A-Z]\):|/\L\1|'
fi
}
```
---
## Quick Reference Card
### Path Conversion Control
| Variable | Scope | Effect |
|----------|-------|--------|
| `MSYS_NO_PATHCONV=1` | Git for Windows | Disables all conversion |
| `MSYS2_ARG_CONV_EXCL="pattern"` | MSYS2 | Excludes specific patterns |
| `MSYS2_ENV_CONV_EXCL="var"` | MSYS2 | Excludes environment variables |
### Shell Detection Variables
| Variable | Available | Purpose |
|----------|-----------|---------|
| `$OSTYPE` | Bash | Quick OS type detection |
| `$MSYSTEM` | MSYS2/Git Bash | Subsystem type (MINGW64/MINGW32/MSYS) |
| `$(uname -s)` | All POSIX | Detailed OS identification |
### cygpath Quick Reference
| Command | Purpose |
|---------|---------|
| `cygpath -u "C:\path"` | Windows → Unix format |
| `cygpath -w "/c/path"` | Unix → Windows format |
| `cygpath -m "/c/path"` | Unix → Mixed format (forward slashes) |
| `cygpath -a "path"` | Convert to absolute path |
### Common Issues & Solutions
| Problem | Solution |
|---------|----------|
| Path with spaces breaks | Quote the path: `"$path"` |
| Flag `/e` converted to path | Use `//e` or `-e` instead |
| Drive duplication `D:\d\` | Use Unix format: `/d/` |
| Windows program needs Windows path | Use `cygpath -w "$unix_path"` |
| Script fails in Claude Code | Set `CLAUDE_CODE_GIT_BASH_PATH` |
---
## Summary
Understanding Git Bash/MINGW path conversion is essential for writing robust cross-platform bash scripts that work on Windows. Key takeaways:
1. **Automatic conversion** happens for Unix-style paths in arguments
2. **Control conversion** using `MSYS_NO_PATHCONV` and `MSYS2_ARG_CONV_EXCL`
3. **Use cygpath** for reliable manual path conversion
4. **Detect platform** using `$OSTYPE`, `$MSYSTEM`, or `uname -s`
5. **Quote all paths** to handle spaces and special characters
6. **Test on target platforms** to catch platform-specific issues
7. **Document requirements** so users know what to expect
With this knowledge, you can write bash scripts that work seamlessly across Linux, macOS, Windows Git Bash, WSL, and other Unix-like environments.