Function Parameters and Return Values
Functions become powerful when they can accept input and produce output. Learn how to pass data into functions and get results back.
Passing Arguments to Functions
Arguments work just like script arguments:
#!/bin/bash
greet() {
echo "Hello, $1!"
}
greet "Alice" # Hello, Alice!
greet "Bob" # Hello, Bob!
Inside the function:
$1,$2, etc. are the function's arguments$#is the number of arguments$@is all arguments
Multiple Arguments
#!/bin/bash
create_user() {
local username="$1"
local email="$2"
local role="${3:-user}" # Default role
echo "Creating user:"
echo " Username: $username"
echo " Email: $email"
echo " Role: $role"
}
create_user "john" "john@example.com" "admin"
create_user "jane" "jane@example.com" # Uses default role
Exercise: Function with Arguments
Pass arguments to a function:
All Arguments with $@
Process any number of arguments:
#!/bin/bash
process_files() {
echo "Processing $# files..."
for file in "$@"; do
echo " - $file"
done
}
process_files "doc1.txt" "doc2.txt" "doc3.txt"
Remember to quote "$@" to preserve argument boundaries!
The return Statement
Functions return exit status (0-255):
#!/bin/bash
is_even() {
if (( $1 % 2 == 0 )); then
return 0 # Success/true
else
return 1 # Failure/false
fi
}
if is_even 4; then
echo "4 is even"
fi
if is_even 7; then
echo "7 is even"
else
echo "7 is odd"
fi
return 0= success/truereturn 1-255= failure/false (different error codes)
Checking Return Values
#!/bin/bash
divide() {
if [ "$2" -eq 0 ]; then
return 1 # Error: division by zero
fi
echo $(( $1 / $2 ))
return 0
}
# Method 1: Check immediately
divide 10 2
if [ $? -eq 0 ]; then
echo "Division successful"
fi
# Method 2: Use in condition
if divide 10 0; then
echo "Success"
else
echo "Division failed!"
fi
Returning Values (Output)
Since return only gives 0-255, use other methods for actual values:
Method 1: Echo and Capture
#!/bin/bash
get_sum() {
echo $(( $1 + $2 ))
}
RESULT=$(get_sum 5 3)
echo "Sum is: $RESULT"
Method 2: Global Variable
#!/bin/bash
get_user_info() {
USER_NAME="$1"
USER_HOME="/home/$1"
}
get_user_info "alice"
echo "Name: $USER_NAME"
echo "Home: $USER_HOME"
Method 3: nameref (Bash 4.3+)
#!/bin/bash
get_double() {
local -n result=$2 # nameref
result=$(( $1 * 2 ))
}
get_double 5 MY_VAR
echo "Double: $MY_VAR"
Exercise: Return Success/Failure
Use return for validation:
Returning Multiple Values
#!/bin/bash
# Method 1: Echo multiple values, parse output
get_dimensions() {
echo "1920 1080"
}
read WIDTH HEIGHT <<< "$(get_dimensions)"
# Method 2: Use an array
get_stats() {
echo "10 20 30"
}
STATS=($(get_stats))
echo "Min: ${STATS[0]}, Max: ${STATS[1]}, Avg: ${STATS[2]}"
# Method 3: Set multiple globals
get_file_info() {
FILE_NAME="$1"
FILE_SIZE=$(stat -f%z "$1" 2>/dev/null || stat -c%s "$1" 2>/dev/null)
FILE_TYPE=$(file -b "$1")
}
Default Parameter Values
#!/bin/bash
greet() {
local name="${1:-World}"
local greeting="${2:-Hello}"
echo "$greeting, $name!"
}
greet # Hello, World!
greet "Alice" # Hello, Alice!
greet "Bob" "Hi" # Hi, Bob!
Validating Arguments
Check arguments at function start:
#!/bin/bash
create_backup() {
# Require at least one argument
if [ $# -lt 1 ]; then
echo "Usage: create_backup <source> [dest]" >&2
return 1
fi
local source="$1"
local dest="${2:-/backup}"
# Validate source exists
if [ ! -e "$source" ]; then
echo "Error: Source not found: $source" >&2
return 1
fi
echo "Backing up $source to $dest"
# cp -r "$source" "$dest"
return 0
}
Passing Arrays to Functions
#!/bin/bash
print_array() {
local arr=("$@")
echo "Array has ${#arr[@]} elements:"
for item in "${arr[@]}"; do
echo " - $item"
done
}
FRUITS=("apple" "banana" "cherry")
print_array "${FRUITS[@]}"
Exercise: Function with Default
Use default parameter value:
Error Handling Pattern
#!/bin/bash
process_file() {
local file="$1"
# Guard clauses
[ -z "$file" ] && { echo "Error: No file specified" >&2; return 1; }
[ ! -f "$file" ] && { echo "Error: File not found: $file" >&2; return 2; }
[ ! -r "$file" ] && { echo "Error: File not readable: $file" >&2; return 3; }
# Main logic
echo "Processing: $file"
cat "$file"
return 0
}
# Usage with error checking
if ! process_file "data.txt"; then
echo "Failed to process file"
exit 1
fi
Common Patterns
Getter Function
get_config_value() {
local key="$1"
grep "^$key=" config.txt | cut -d= -f2
}
DB_HOST=$(get_config_value "database_host")
Validator Function
is_valid_ip() {
[[ $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]
}
if is_valid_ip "$IP"; then
echo "Valid IP"
fi
Factory Function
create_temp_file() {
local prefix="${1:-tmp}"
mktemp "/tmp/${prefix}.XXXXXX"
}
TEMP=$(create_temp_file "backup")
echo "Created: $TEMP"
Key Takeaways
- Function arguments:
$1,$2, etc. (like script arguments) - Use
"$@"to pass all arguments (quoted) return Nsets exit status (0=success, 1-255=failure)- Echo to "return" actual values, capture with
$() - Use
${1:-default}for default parameters - Always validate required arguments
- Use
localfor function variables (covered next lesson) - Return early for error conditions (guard clauses)

