Bash Cheatsheet
Functions
Use this Bash reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Defining Functions
# Syntax 1: function keyword function greet { echo "Hello, $1" } # Syntax 2: POSIX-compatible (preferred) greet() { echo "Hello, $1" } # One-liner greet() { echo "Hello, $1"; } # Call a function (just like a command) greet "Alice"
Arguments and Parameters
myfunc() { echo "Number of args: $#" echo "First arg: $1" echo "Second arg: $2" echo "All args: $@" # each separately quoted — use this echo "All as string: $*" # joined by IFS — use $@ instead echo "Function name: ${FUNCNAME[0]}" } myfunc one two three
Return Values and Exit Status
# Return only an integer exit status (0-255) add_numbers() { echo $(( $1 + $2 )) # output result via stdout return 0 # return exit status } result=$(add_numbers 3 4) # capture stdout echo "Result: $result" # 7 check_positive() { (( $1 > 0 )) && return 0 || return 1 } if check_positive 5; then echo "positive" fi echo "Status: $?"
Local Variables
outer="global" myfunc() { local inner="local only" local -i count=0 # local integer local -r CONST="fixed" # local read-only outer="modified" # modifies the global echo "$inner" } myfunc echo "$inner" # empty — local is gone echo "$outer" # "modified"
Default and Named Parameters
# Default values for missing arguments greet() { local name="${1:-World}" echo "Hello, $name" } greet # Hello, World greet "Alice" # Hello, Alice # Named parameters via local parsing connect() { local host="${1:?host is required}" local port="${2:-5432}" local db="${3:-mydb}" echo "Connecting to $host:$port/$db" } connect localhost connect localhost 5433 testdb
Passing Arrays to Functions
# Pass by name (nameref, Bash 4.3+) process_array() { declare -n arr=$1 # nameref to the passed variable name for item in "${arr[@]}"; do echo "$item" done } data=(a b c) process_array data # Pass all elements as arguments (simple) print_all() { for item in "$@"; do echo "$item" done } print_all "${data[@]}" # Return an array (via nameref) get_files() { declare -n _result=$1 _result=( *.txt ) } declare -a files get_files files echo "${files[@]}"
Function Scope and Subshells
# Variables declared inside a function without local are GLOBAL no_local() { shared="set inside" } no_local echo "$shared" # "set inside" # Running a function in a subshell isolates changes (no_local) echo "$shared" # unaffected # Function that changes directory safely in_dir() { (cd "$1" && "${@:2}") # subshell: parent dir unchanged } in_dir /tmp ls
Recursive Functions
factorial() { local n=$1 if (( n <= 1 )); then echo 1 else local sub=$(factorial $(( n - 1 ))) echo $(( n * sub )) fi } factorial 5 # 120 # Fibonacci fib() { local n=$1 (( n <= 1 )) && echo $n && return echo $(( $(fib $(( n-1 ))) + $(fib $(( n-2 ))) )) }
Function Libraries (Sourcing)
# lib/utils.sh log() { echo "[$(date '+%H:%M:%S')] $*" >&2; } die() { log "ERROR: $*"; exit 1; } warn() { log "WARN: $*"; } info() { log "INFO: $*"; } # main script source lib/utils.sh # or . lib/utils.sh info "Starting..." command_that_might_fail || die "it failed"
Traps and Cleanup Functions
cleanup() { echo "Cleaning up..." rm -f /tmp/myapp_$$.* } trap cleanup EXIT # run cleanup on any exit trap 'echo "Interrupted"' INT # Ctrl+C trap 'echo "Terminated"' TERM trap '' HUP # ignore SIGHUP # Remove a trap trap - EXIT # Trap with ERR for debugging trap 'echo "Error at line $LINENO"' ERR
Special Variables Inside Functions
| Variable | Meaning |
|---|---|
$1 … $N | Positional args to the function |
$# | Number of args to the function |
$@ | All args (separately quoted) |
$* | All args (as one string with IFS) |
$? | Exit status of last command |
${FUNCNAME[0]} | Current function name |
${FUNCNAME[1]} | Caller function name |
${BASH_LINENO[0]} | Line number of call site |
whoami_func() { echo "I am: ${FUNCNAME[0]}" echo "Called from: ${FUNCNAME[1]} at line ${BASH_LINENO[0]}" } caller_func() { whoami_func } caller_func
Overriding and Wrapping Commands
# Wrap a command (save original with command) ls() { command ls --color=auto "$@" } # Temporarily override for testing my_date() { echo "2024-01-01"; } date() { my_date; } # override date builtin shim # Check if a function is defined declare -f myfunc > /dev/null && echo "defined" type myfunc # shows "myfunc is a function" # Undefine a function unset -f myfunc
Pipeline and Process Substitution in Functions
# Functions work in pipelines double() { while IFS= read -r line; do echo "$line $line" done } echo "hello" | double # Returning multiple values via stdout get_stats() { local file=$1 local lines=$(wc -l < "$file") local words=$(wc -w < "$file") echo "$lines $words" } read lines words <<< "$(get_stats file.txt)" echo "Lines: $lines, Words: $words"