Functions
Copy-pasting the same code throughout your script? Functions let you write it once and call it anywhere.
Defining Functions
Two syntaxes (both work):
# Traditional
function greet {
echo "Hello!"
}
# Shorthand (more common)
greet() {
echo "Hello!"
}
Calling Functions
#!/bin/bash
greet() {
echo "Hello, World!"
}
# Call the function
greet
greet
greet
Define Before Calling
Functions must be defined before they're called. Put them at the top of your script.
Function Arguments
Functions receive arguments just like scripts - $1, $2, etc.:
#!/bin/bash
greet() {
echo "Hello, $1!"
}
greet "Alice"
greet "Bob"
Multiple Arguments
#!/bin/bash
create_user() {
local username="$1"
local email="$2"
echo "Creating user: $username"
echo "Email: $email"
}
create_user "john" "john@example.com"
Return Values
Functions return exit codes (0-255), not arbitrary values:
#!/bin/bash
is_root() {
if [[ "$EUID" -eq 0 ]]; then
return 0 # success/true
else
return 1 # failure/false
fi
}
if is_root; then
echo "Running as root"
else
echo "Not root"
fi
Return Data via echo
For actual values, use command substitution:
#!/bin/bash
get_timestamp() {
echo "$(date +%Y%m%d_%H%M%S)"
}
timestamp=$(get_timestamp)
echo "Timestamp: $timestamp"
Local Variables
Variables inside functions are global by default. Use local to keep them contained:
#!/bin/bash
test_scope() {
global_var="I'm global"
local local_var="I'm local"
}
test_scope
echo "$global_var" # Works
echo "$local_var" # Empty - local is gone
Always Use local
Make variables local inside functions unless you specifically need them global. Prevents naming collisions and bugs.
Practical Examples
Logging Function
#!/bin/bash
log() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message"
}
log "INFO" "Script started"
log "WARN" "Low disk space"
log "ERROR" "Connection failed"
Validation Function
#!/bin/bash
validate_email() {
local email="$1"
if [[ "$email" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then
return 0
else
return 1
fi
}
if validate_email "user@example.com"; then
echo "Valid email"
else
echo "Invalid email"
fi
Utility Functions
#!/bin/bash
die() {
echo "ERROR: $1" >&2
exit "${2:-1}"
}
require_root() {
[[ "$EUID" -eq 0 ]] || die "This script requires root"
}
require_command() {
command -v "$1" &>/dev/null || die "Required command not found: $1"
}
# Usage
require_root
require_command "curl"
require_command "jq"
echo "All checks passed!"
All Arguments: $@
#!/bin/bash
process_files() {
for file in "$@"; do
echo "Processing: $file"
done
}
process_files file1.txt file2.txt file3.txt
What does 'local' do in a function?
Quick Reference
| Syntax | Purpose |
|---|---|
name() { ... } | Define function |
name | Call function |
$1, $2 | Function arguments |
$@ | All arguments |
local var | Local variable |
return 0/1 | Return exit code |
$(function) | Capture output |
Key Takeaways
- Functions group reusable code
- Define before calling
- Arguments via
$1,$2,$@ - Use
localfor function variables returnsets exit code (0=success)- Capture output with
$(function_name) - Build a library of utility functions
Next: understanding exit codes.