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

VariableMeaning
$1$NPositional 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"