Table of Contents
Getting Started
Script Mode
Run gosh scripts by passing the script file as an argument:
./gosh script.sh
Or directly with gosh:
gosh script.sh arg1 arg2
Cross-Platform Script Execution
Gosh provides seamless script execution across all platforms with platform-specific shebang handling:
- Unix/Linux/macOS: Scripts with shebangs run with their specified interpreters (bash, zsh, etc.). Missing interpreters show errors, missing shebangs get a gosh pun warning!
- Windows: Scripts with
.sh
extension or shell shebangs are automatically detected and executed through gosh - no "not a valid Win32 application" errors! - Cross-platform commands: Use gosh's dual command support for maximum compatibility
Shebang Line
Start your scripts with a shebang line to specify the interpreter. Gosh handles shebangs differently on each platform:
Unix-like Platforms (Linux, macOS)
Shebangs are respected and scripts run with the specified interpreter:
#!/bin/bash # Runs with bash
#!/usr/bin/env zsh # Runs with zsh
#!/usr/bin/env python3 # Runs with python3
#!/usr/bin/env gosh # Runs with gosh
Windows Platform
Shebangs are recognized but all scripts run through gosh for compatibility:
#!/usr/bin/env gosh # Recommended for cross-platform scripts
#!/bin/gosh # Direct path (recognized but runs through gosh)
#!/bin/sh # Generic shell (recognized but runs through gosh)
#!/bin/bash # Bash-compatible (recognized but runs through gosh)
Making Scripts Executable
On Unix/macOS:
chmod +x script.sh
./script.sh
On Windows:
No need to make scripts executable - gosh automatically detects and runs them! Gosh, that's convenient!
# All of these work on Windows:
./script.sh
gosh script.sh
script.sh # If gosh is in PATH
Windows-Specific Features
Gosh provides excellent Windows support with automatic shell script execution - gosh, it's about time!
Automatic Script Detection
On Windows, gosh automatically detects and executes shell scripts that would normally fail with "not a valid Win32 application" errors:
- File Extension Detection: Scripts with
.sh
extension are automatically recognized - Shebang Detection: Scripts with shell shebang lines (
#!/bin/sh
,#!/usr/bin/env gosh
, etc.) work seamlessly - Transparent Execution: Scripts are executed through gosh itself, providing full compatibility
Cross-Platform Script Examples
#!/usr/bin/env gosh
# This script works identically on Windows, macOS, and Linux
# Gosh, cross-platform scripting has never been easier!
echo "Running on Windows with gosh!"
echo "Script arguments: $@"
# Use cross-platform commands
ls -la # Works on all platforms
echo "Files listed above"
# Windows-compatible commands also work
dir -l # Windows-style listing
type README.md # Windows-style file display
# Environment variables work the same way
export MY_VAR="cross-platform value"
echo "MY_VAR: $MY_VAR"
echo "Gosh darn it, that's some fine cross-platform scripting!"
Windows Path Handling
Gosh handles both forward slashes and backslashes on Windows:
# Both path styles work on Windows
cd ~/Documents # Unix-style (works everywhere)
cd ~\Documents # Windows-style (works on Windows)
# Script paths work with both separators
./scripts/build.sh # Forward slashes
.\scripts\build.sh # Backslashes
# Gosh automatically handles the differences!
No More "Not a Valid Win32 Application" Errors
Before gosh's Windows shell script support:
# This would fail on Windows:
C:\> script.sh
'script.sh' is not recognized as an internal or external command,
operable program or batch file.
# Or worse:
C:\> .\script.sh
Access is denied.
With gosh's automatic detection - gosh, it just works!
# All of these work seamlessly on Windows:
gosh> ./script.sh arg1 arg2
gosh> script.sh arg1 arg2
gosh> gosh script.sh arg1 arg2
# Output:
Hello from gosh script!
Arguments: arg1 arg2
Gosh, that was easy!
Basic Script Structure
Example Script
#!/usr/bin/env gosh
# Example gosh script - gosh, this is neat!
echo "Hello from gosh!"
pwd
export MY_VAR="test" # Environment variable
local TEMP_COUNT=42 # Local variable (function scope)
echo "MY_VAR is: $MY_VAR"
# Pipe examples - gosh, pipes are powerful!
echo "testing pipe functionality" | wc -w
ls -la | head -5
cat /etc/passwd | grep root | wc -l
# Gosh darn it, that's some fine scripting!
Variable Expansion
Gosh supports several forms of variable expansion:
Variable Declaration Requirements
In gosh, all variables must be explicitly declared with either local
or export
:
# Local variables (current shell only)
local NAME="World"
local COUNT=42
# Environment variables (exported to child processes)
export MY_VAR="Hello"
export PATH="$PATH:/new/path"
Basic Variable Expansion
local NAME="World" # Local variable
echo "Hello, $NAME!"
echo "Path: ${HOME}/Documents"
Environment Variables
# Set environment variables
export MY_VAR="Hello"
export PATH="$PATH:/new/path"
# Use environment variables
echo $MY_VAR
echo "Current PATH: $PATH"
Variable Usage Examples
# Project configuration
export PROJECT_NAME="my-app" # Environment variable
export PROJECT_DIR="$HOME/projects/$PROJECT_NAME" # Environment variable
local BUILD_DIR="$PROJECT_DIR/build" # Local variable
# Create directory structure
mkdir -p $BUILD_DIR
cd $PROJECT_DIR
echo "Working on $PROJECT_NAME in $PROJECT_DIR"
Command Substitution
Execute commands and use their output in your scripts:
Using $(command)
Syntax
# Store command output in variables
local CURRENT_DIR="$(pwd)"
export BUILD_DATE="$(date +%Y-%m-%d)"
echo "Current directory: $CURRENT_DIR"
echo "Today is $BUILD_DATE"
echo "Found $(ls *.txt | wc -l) text files in $(pwd)"
Using Backticks
# Store command output in variables
local FILE_COUNT="`ls | wc -l`"
export CURRENT_USER="`whoami`"
echo "Files: $FILE_COUNT"
echo "Current user: $CURRENT_USER"
Practical Examples
# Backup with timestamp
local DATE="$(date +%Y%m%d_%H%M%S)" # Local variable
cp important.txt "backup_$DATE.txt"
# Dynamic file processing
for file in $(ls *.log); do
echo "Processing $file..."
local BASE_NAME="$(basename $file .log)" # Local variable
grep "ERROR" $file > "errors_$BASE_NAME.txt"
done
# System information
if command -v uname >/dev/null 2>&1; then
local SYSTEM="$(uname -s)" # Local variable
else
local SYSTEM="Windows" # Local variable
fi
export CURRENT_USER="$(whoami)" # Environment variable
echo "System: $SYSTEM"
echo "User: $CURRENT_USER"
echo "Home: $HOME"
Tilde Expansion
Gosh expands tilde (~
) to represent home directories with cross-platform path separator support:
# Expand to current user's home
ls ~/Documents
cp file.txt ~/backup/
cd ~
# Expand to specific user's home
cd ~user/projects
ls ~admin/logs
Windows Backslash Support
On Windows, gosh supports both forward slashes and backslashes for tilde expansion:
# Windows-style paths with backslashes
cd ~\Documents
ls ~\backup\
cp file.txt ~\Projects\myapp\
# Mixed separators work too
cd ~user\projects
ls ~admin\logs
Cross-Platform Compatibility
Your scripts can use either path separator style and work across platforms:
# Both styles work on Windows
cd ~/Documents # Unix-style (works everywhere)
cd ~\Documents # Windows-style (works on Windows)
# The path separator style is preserved in expansions
echo ~/path # Expands to /home/user/path on Unix
echo ~\path # Expands to C:\Users\user\path on Windows
Practical Examples
# Backup to home directory
tar -czf ~/backups/project_$(date +%Y%m%d).tar.gz .
# Configuration files (cross-platform)
cp config.ini ~/.config/myapp/
echo "export PATH=\$PATH:~/bin" >> ~/.bashrc
# Windows-specific examples
copy config.ini ~\AppData\Local\myapp\
xcopy /s source\* ~\backup\
Glob Patterns
Use wildcards for filename matching:
# Match all .go files
ls *.go
# Match single character
rm temp_file_?.txt
# Character classes
echo [Hh]ello*
ls [abc]*
# More complex patterns
find . -name "*.{js,ts,jsx,tsx}"
ls test_[0-9][0-9].log
Practical Examples
# Process all source files
for file in *.{c,cpp,h}; do
echo "Compiling $file..."
gcc -c $file
done
# Clean temporary files
rm -f *.tmp *.bak *~
rm -f test_*.log debug_[0-9]*.txt
Input/Output Redirection
Input Redirection
# Read from file
cat < input.txt
sort < unsorted.txt
wc -l < data.csv
Output Redirection
# Overwrite file
echo "Hello" > output.txt
ls -la > file_list.txt
date > timestamp.txt
# Append to file
echo "World" >> output.txt
date >> log.txt
echo "Process completed" >> status.log
Combining Redirection
# Sort a file and save result
sort < input.txt > sorted.txt
# Process and save
grep "ERROR" < application.log > errors.txt
cut -d',' -f1,3 < data.csv > names_scores.csv
Practical Examples
# Log script execution
echo "Script started at $(date)" > script.log
echo "Processing files..." >> script.log
# Generate reports
echo "Daily Report - $(date)" > daily_report.txt
echo "===================" >> daily_report.txt
ps aux | grep myapp >> daily_report.txt
df -h >> daily_report.txt
Pipes and Command Chaining
Using Pipes
# Chain commands with pipes
ls | grep ".go" | wc -l
cat file.txt | sort | uniq
ps aux | grep gosh | head -5
Command Chaining with Semicolons
# Execute commands sequentially
echo "First command"; echo "Second command"; pwd
ls; echo "Files listed"; pwd
# Combine with pipes and redirection
ls *.go > go_files.txt; cat go_files.txt | wc -l
Complex Pipeline Examples
# Log analysis
cat access.log | grep "$(date +%Y-%m-%d)" | cut -d' ' -f1 | sort | uniq -c | sort -nr
# File processing
find . -name "*.txt" | xargs grep "TODO" | cut -d: -f1 | sort | uniq
# System monitoring
ps aux | awk '{print $3, $11}' | sort -nr | head -10
Background Execution
Run commands in the background:
# Run command in background
sleep 10 &
long_running_process &
# Continue with other commands
echo "Background job started"
ps aux | grep sleep
Practical Examples
# Start multiple background tasks
echo "Starting background tasks..."
./data_processor input1.csv &
./data_processor input2.csv &
./data_processor input3.csv &
# Wait for completion
echo "Waiting for tasks to complete..."
wait
echo "All tasks completed"
Functions
Gosh supports user-defined functions with full positional parameter support, enabling you to create reusable code blocks within your scripts.
Function Definition
Define functions using the standard shell syntax:
# Basic function definition
function_name() {
# Function body
echo "Hello from function!"
}
# Alternative syntax
function function_name {
echo "Hello from function!"
}
Calling Functions
Call functions by name, optionally passing arguments:
# Call function without arguments
function_name
# Call function with arguments
greet "World" "from" "gosh"
Positional Parameters
Functions have access to special variables for handling parameters:
greet() {
echo "Function name: $0"
echo "First parameter: $1"
echo "Second parameter: $2"
echo "All parameters: $@"
echo "Parameter count: $#"
}
# Call the function
greet "Alice" "Bob" "Charlie"
# Output:
# Function name: greet
# First parameter: Alice
# Second parameter: Bob
# All parameters: Alice Bob Charlie
# Parameter count: 3
Parameter Variables
$0
- Function name$1, $2, $3, ...
- Individual positional parameters$#
- Number of parameters passed$@
- All parameters as separate words$*
- All parameters as a single string
Practical Examples
File Processing Function
process_file() {
if [ $# -eq 0 ]; then
echo "Usage: $0 "
return 1
fi
local file="$1" # Local variable (function scope)
echo "Processing file: $file"
if [ -f "$file" ]; then
local line_count="$(wc -l "$file" | cut -d' ' -f1)" # Local variable
local todo_count="$(grep -c "TODO" "$file" || echo "0")" # Local variable
echo "Lines: $line_count"
echo "TODOs: $todo_count"
else
echo "Error: File '$file' not found"
return 1
fi
}
# Usage
process_file "script.sh"
process_file "README.md"
Backup Function
backup_file() {
local source="$1" # Local variable (function scope)
local backup_dir="${2:-./backups}" # Local variable with default value
if [ $# -eq 0 ]; then
echo "Usage: $0 [backup_directory]"
return 1
fi
mkdir -p "$backup_dir"
local timestamp="$(date +%Y%m%d_%H%M%S)" # Local variable
local basename="$(basename $source)" # Local variable
cp "$source" "$backup_dir/$basename.$timestamp"
echo "Backed up $source to $backup_dir"
}
# Usage
backup_file "important.txt"
backup_file "config.ini" "/home/user/backups"
System Information Function
system_info() {
echo "=== System Information ==="
local current_date="$(date)" # Local variable
local current_user="$(whoami)" # Local variable
local current_dir="$(pwd)" # Local variable
local disk_usage="$(df -h . | tail -1 | awk '{print $5}')" # Local variable
echo "Date: $current_date"
echo "User: $current_user"
echo "Directory: $current_dir"
echo "Disk usage: $disk_usage"
if [ $# -gt 0 ]; then
echo "Additional info requested: $@"
fi
}
# Usage
system_info
system_info "memory" "processes"
Nested Function Calls
Functions can call other functions, with each maintaining its own parameter context:
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
process_with_logging() {
log_message "Starting process: $1"
# Simulate processing
echo "Processing $1..."
sleep 1
log_message "Completed process: $1"
}
# Usage
process_with_logging "data_file.csv"
process_with_logging "config_update"
Function Management
List Defined Functions
# List all defined functions
functions
# Show function definitions
type function_name
Complete Function Example
#!/usr/bin/env gosh
# Project management script with functions
# Configuration
export PROJECT_ROOT="$(pwd)" # Environment variable
export LOG_FILE="project.log" # Environment variable
# Logging function
log() {
echo "[$(date '+%H:%M:%S')] $@" | tee -a "$LOG_FILE"
}
# Error handling function
error_exit() {
log "ERROR: $1"
exit 1
}
# Build function
build_project() {
local target="${1:-all}"
log "Building target: $target"
case "$target" in
"clean")
rm -rf build/
log "Clean completed"
;;
"compile")
mkdir -p build
log "Compilation started"
# Add compilation commands here
log "Compilation completed"
;;
"all")
build_project clean
build_project compile
;;
*)
error_exit "Unknown build target: $target"
;;
esac
}
# Test function
run_tests() {
log "Running tests with $# test files"
for test_file in "$@"; do
if [ -f "$test_file" ]; then
log "Running test: $test_file"
# Execute test file
."/$test_file" || error_exit "Test failed: $test_file"
else
log "Warning: Test file not found: $test_file"
fi
done
log "All tests completed successfully"
}
# Main execution
log "Project script started"
build_project "$1"
if [ "$2" = "test" ]; then
run_tests test_*.sh
fi
log "Project script completed"
Aliases in Scripts
Create and use aliases within scripts:
# Create aliases
alias ll="ls -la"
alias grep="grep --color=auto"
alias ..="cd .."
# Use aliases
ll
grep "pattern" file.txt
..
Best Practices
Script Structure
- Always start with a shebang line
- Add comments to explain complex logic
- Use meaningful variable names
- Group related commands together
Error Handling
# Check if file exists before processing
if [ -f "input.txt" ]; then
cat input.txt | process_data
else
echo "Error: input.txt not found"
exit 1
fi
Variable Usage
# Use quotes to handle spaces in filenames
local FILE_NAME="my document.txt" # Local variable
cp "$FILE_NAME" "backup_$FILE_NAME"
# Use braces for clarity
local CURRENT_TIME="$(date)" # Local variable
echo "Processing ${FILE_NAME} at $CURRENT_TIME"
Complete Example Script
#!/usr/bin/env gosh
# Project build script
# Usage: ./build.sh [clean|build|test]
# Configuration
export PROJECT_NAME="my-project" # Environment variable
local BUILD_DIR="./build" # Local variable
local SRC_DIR="./src" # Local variable
# Functions
clean_build() {
echo "Cleaning build directory..."
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
}
build_project() {
echo "Building $PROJECT_NAME..."
# Copy source files
cp -r "$SRC_DIR"/* "$BUILD_DIR"/
# Process files
find "$BUILD_DIR" -name "*.template" | while read file; do
echo "Processing template: $file"
sed "s/{{PROJECT_NAME}}/$PROJECT_NAME/g" "$file" > "${file%.template}"
rm "$file"
done
echo "Build completed at $(date)"
}
run_tests() {
echo "Running tests..."
find "$BUILD_DIR" -name "*_test.sh" -exec {} \;
}
# Main script logic
case "$1" in
clean)
clean_build
;;
build)
clean_build
build_project
;;
test)
run_tests
;;
*)
echo "Usage: $0 {clean|build|test}"
exit 1
;;
esac
echo "Script completed successfully!"
Comments
Use comments to document your scripts: