ShBash · Lesson 4 of 8

Functions

Bash functions are reusable blocks of code. They work differently from functions in other languages — no return values, just exit codes and stdout.

Bash
#!/bin/bash

# Function definition
greet() {
    local name="$1"   # local — scoped to function
    echo "Hello, $name!"
}

# Call it
greet "Alice"
greet "World"

# Arguments work like script arguments: $1, $2, $@
log() {
    local level="$1"
    shift              # shift removes $1, moves $2 to $1, etc.
    echo "[$(date +%H:%M:%S)] [$level] $*"
}

log "INFO" "Server started"
log "ERROR" "Connection refused"

# Return an exit code (0=success, non-zero=failure)
is_even() {
    local n="$1"
    [ $((n % 2)) -eq 0 ]   # the exit code of the last command is returned
}

if is_even 4; then echo "4 is even"; fi
if ! is_even 3; then echo "3 is odd"; fi

# "Return" a value via echo + command substitution
to_uppercase() {
    echo "$1" | tr '[:lower:]' '[:upper:]'
}

result=$(to_uppercase "hello world")
echo "$result"   # HELLO WORLD
Bash
#!/bin/bash

# Useful pattern: functions that do one thing
check_dependency() {
    if ! command -v "$1" &>/dev/null; then
        echo "ERROR: '$1' is not installed. Please install it first." >&2
        return 1
    fi
}

check_dependencies() {
    local failed=0
    for dep in "$@"; do
        check_dependency "$dep" || ((failed++))
    done
    return $failed
}

# Error handling
die() {
    echo "ERROR: $*" >&2
    exit 1
}

require_file() {
    [ -f "$1" ] || die "Required file not found: $1"
}

# Example usage
check_dependencies git curl jq || die "Missing dependencies"
require_file "config.json"
◆ Note
Use local for all variables inside functions. Without local, Bash variables are global by default — a function setting x=5 would change a global x variable, which is a nasty source of bugs.