Bash
Functions
Bash functions and modular scripts
Functions
Functions are reusable blocks of code that help organize and modularize scripts.
Function Basics
# Define a function
my_function() {
echo "This is a function"
}
# Alternative syntax
function my_function {
echo "This is a function"
}
# Call the function
my_functionFunction Parameters
# Function with parameters
greet() {
local name=$1 # first parameter
local age=$2 # second parameter
echo "Hello $name, you are $age years old"
}
# Call with arguments
greet "Alice" 30
greet "Bob" 25
# Access all parameters
print_all() {
echo "All arguments: $@"
echo "Argument count: $#"
for arg in "$@"; do
echo "- $arg"
done
}
print_all one two threeReturn Values
# Exit status (0 = success, non-zero = failure)
check_file() {
local file=$1
if [ -f "$file" ]; then
return 0 # success
else
return 1 # failure
fi
}
# Use return value
if check_file "/etc/passwd"; then
echo "File exists"
else
echo "File not found"
fi
# Return data through echo
get_double() {
local num=$1
echo $((num * 2))
}
result=$(get_double 5)
echo "Result: $result" # Result: 10Local Variables
# Local variables avoid polluting global scope
my_function() {
local local_var="I'm local"
global_var="I'm global"
echo "Local: $local_var"
}
my_function
echo "Global: $global_var" # outputs: I'm global
echo "Local: $local_var" # outputs nothing (local is gone)Recursive Functions
# Factorial using recursion
factorial() {
local n=$1
if [ $n -le 1 ]; then
echo 1
else
local prev=$(factorial $((n-1)))
echo $((n * prev))
fi
}
echo "5! = $(factorial 5)" # 120
# Countdown using recursion
countdown() {
local n=$1
if [ $n -gt 0 ]; then
echo $n
countdown $((n-1))
fi
}
countdown 5Function Error Handling
# Check exit status in function
safe_copy() {
local src=$1
local dst=$2
if [ ! -f "$src" ]; then
echo "Error: Source file not found: $src" >&2
return 1
fi
cp "$src" "$dst" || return $?
return 0
}
# Use the function
if safe_copy "file1.txt" "file2.txt"; then
echo "Copy successful"
else
echo "Copy failed"
fiFunction Documentation
#!/bin/bash
# Function: add
# Description: Add two numbers
# Arguments:
# $1 - First number
# $2 - Second number
# Returns: Sum of the two numbers
add() {
local a=$1
local b=$2
echo $((a + b))
}
result=$(add 5 3)
echo "5 + 3 = $result"Advanced Patterns
Default Parameters
# Use default value if parameter not provided
greet() {
local name=${1:-"Guest"}
local greeting=${2:-"Hello"}
echo "$greeting, $name!"
}
greet # Hello, Guest!
greet "Alice" # Hello, Alice!
greet "Bob" "Hi" # Hi, Bob!Named Parameters
# Parse named parameters
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-n|--name) name="$2"; shift 2 ;;
-a|--age) age="$2"; shift 2 ;;
*) echo "Unknown option: $1"; return 1 ;;
esac
done
}
parse_args --name "Alice" --age 30
echo "Name: $name, Age: $age"Pipeline Functions
# Function that works in pipeline
count_lines() {
wc -l < /dev/stdin
}
# Use in pipeline
ls -la | count_linesFunction Library
# Create reusable library
# lib.sh
log_info() {
echo "[INFO] $1"
}
log_error() {
echo "[ERROR] $1" >&2
}
# Use library in script
source ./lib.sh
log_info "Application started"
log_error "Something went wrong"Practical Examples
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"
fiRetry Function
retry() {
local max_attempts=3
local attempt=1
while [ $attempt -le $max_attempts ]; do
if "$@"; then
return 0
fi
echo "Attempt $attempt failed. Retrying..." >&2
((attempt++))
sleep 2
done
return 1
}
retry curl https://example.comBest Practices
- Use descriptive function names
- Always use
localfor variables in functions - Document complex functions with comments
- Check parameter count at function start
- Return meaningful exit codes
- Use consistent naming conventions
- Keep functions focused and single-purpose
- Test functions independently
- Avoid modifying global variables
- Return data via echo, status via exit code