Functions in Bash Scripts
Organise scripts into reusable functions, pass arguments to them and understand the difference between exit codes and printed output.
Why functions?
Suppose your script prints a banner in five places. Copying the same lines five times is messy, and fixing a mistake means fixing it five times. A function is a named block of commands. You write it once and run it by name whenever you need it.
Defining and calling
greet() {
echo "Hello from a function"
}
greet
greet
The definition has a name, () and a body in { }. Writing the name greet calls the function, which runs its body. This script prints the message twice.
Bash reads a script from top to bottom, so you must define a function before you call it.
Passing arguments
Functions receive arguments in the same way scripts do, as $1, $2 and so on.
greet() {
echo "Hello, $1!"
}
greet "Alex"
greet "Sam"
This prints Hello, Alex! and Hello, Sam!. Inside a function, $1 is the first argument given to the function, not to the script. $# is the number of arguments and $@ is all of them.
Local variables
By default a variable set inside a function is global, which means it stays visible and can overwrite variables elsewhere in the script. Use local to keep a variable inside the function.
add() {
local total=$(( $1 + $2 ))
echo "$total"
}
Make local a habit. It prevents confusing bugs in longer scripts.
Giving results back
A function can give something back in two different ways. They are not the same thing.
1. The exit code
return ends the function with a number from 0 to 255. By convention 0 means success and any other number means failure. if reads this value.
is_even() {
if [ $(( $1 % 2 )) -eq 0 ]; then
return 0
else
return 1
fi
}
if is_even 10; then
echo "10 is even"
fi
% gives the remainder after division, so 10 % 2 is 0.
2. Printed output
To give back real data, such as a number or a sentence, print it with echo and capture it with command substitution:
square() {
echo $(( $1 * $1 ))
}
result=$(square 7)
echo "7 squared is $result"
return for answers. It only handles 0 to 255 and is meant for success or failure. Use echo for data.A complete example
#!/bin/bash
log() {
echo "[$(date +%H:%M:%S)] $1"
}
check_disk() {
local usage
usage=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$usage" -gt 80 ]; then
log "WARNING: disk is ${usage}% full"
return 1
fi
log "Disk is fine (${usage}%)"
return 0
}
log "Starting checks"
check_disk
log "Done"
df / shows disk usage, awk picks the percentage column and tr -d '%' removes the % sign so the value can be compared as a number. The main part of the script is a short list of steps: log, check the disk, log. That is the benefit of functions: a short, readable script with the details hidden in named blocks.