Functions¶
Functions are what separate a 50-line script from a 500-line one — reuse logic, reduce repetition, and make code testable.
Learning Objectives¶
- Define and call functions in bash
- Pass arguments to functions and return values
- Use
localto scope variables inside functions - Source a library of functions from another file
Defining and Calling Functions¶
# Two equivalent syntaxes
greet() {
echo "Hello, $1"
}
function greet {
echo "Hello, $1"
}
# Call it
greet "Nikhil"
Prefer the name() {} syntax
The function name {} syntax is bash-specific. The name() {} syntax works in POSIX sh and bash. Use name() for portability.
Arguments¶
Functions receive arguments the same way scripts do — as $1, $2, etc. Inside the function, $@ is the function's arguments, not the script's:
Local Variables¶
Without local, variables set inside a function pollute the global scope:
bad_function() {
x=10 # global — visible outside the function
}
good_function() {
local x=10 # local — invisible outside the function
}
Always use local for function variables
Forgetting local means any variable name collision between your function and the calling code will cause subtle bugs. Make local the default.
Return Values¶
return sets the exit code (0-255). To return a string, print it and capture with $():
is_even() {
local n="$1"
if (( n % 2 == 0 )); then
return 0 # true/success
else
return 1 # false/failure
fi
}
get_extension() {
local filename="$1"
echo "${filename##*.}"
}
# Usage
if is_even 42; then
echo "42 is even"
fi
ext=$(get_extension "report.pdf")
echo "Extension: $ext"
Sourcing Function Libraries¶
Define reusable functions in a separate file and source them:
# ~/scripts/lib/utils.sh
log() {
echo "[$(date +%H:%M:%S)] $*"
}
die() {
echo "ERROR: $*" >&2
exit 1
}
require_file() {
[[ -f "$1" ]] || die "Required file not found: $1"
}
# In your script
source ~/scripts/lib/utils.sh
# or: . ~/scripts/lib/utils.sh
log "Starting backup"
require_file "/etc/backup.conf"
Common Mistakes¶
Functions must be defined before they are called
Bash reads scripts top to bottom. If you call a function before defining it, you get command not found. Define or source all functions at the top of the script.
return only works in functions
Using return outside a function exits the current source operation, not the script. Use exit to exit the script.
Practice Exercises¶
Warm-Up (run and observe)¶
- Write a function
say_hellothat takes a name and prints"Hello, <name>!". Call it three times with different names. - Write a function
is_directorythat returns0if its argument is a directory and1otherwise. Test it withif is_directory "/etc". - What happens if you define a function with the same name as a built-in command like
echo? How do you call the realechoafter that?
Main (write a short script)¶
Create ~/scripts/lib/utils.sh with a small utility library, then write ~/scripts/backup_simple.sh that sources it:
# ~/scripts/lib/utils.sh
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
die() { echo "ERROR: $*" >&2; exit 1; }
info() { echo "INFO: $*"; }
success() { echo "OK: $*"; }
#!/usr/bin/env bash
set -euo pipefail
source "$(dirname "$0")/lib/utils.sh"
SOURCE="${1:?Usage: $0 <source> <dest>}"
DEST="${2:?Usage: $0 <source> <dest>}"
[[ -d "$SOURCE" ]] || die "Source does not exist: $SOURCE"
log "Starting backup: $SOURCE -> $DEST"
cp -r "$SOURCE" "$DEST"
success "Backup complete"
Stretch¶
- Write a function
retrythat takes a command and a max attempt count, runs the command, and retries up to N times on failure. - Research how to list all functions defined in your current shell session. What command shows them?
- What is the difference between sourcing a file with
.vssource? Is there any practical difference in bash?
Interview Questions¶
- Why should you use
localfor variables inside functions?
Show answer
Without local, variables are global — they can accidentally overwrite variables in the calling scope or leak values to subsequent code. local scopes the variable to the function, making functions self-contained and safe to reuse.
- How do you return a string value from a bash function?
Show answer
Print the value with echo (or printf) inside the function, then capture it with command substitution: result=$(my_function arg). return can only pass an integer exit code (0-255), not a string.
- What does
source file.shdo, and how is it different frombash file.sh?
Show answer
source file.sh (or . file.sh) runs the file in the current shell process — functions and variables defined in it become available in the current session. bash file.sh runs the file in a new child process — nothing defined in it persists after it exits.