Functions turn a pile of working commands into a named, reusable step. In bash they are lighter than in most languages — no typed parameters, no real return values — and that lightness is exactly why learning their three honest mechanisms (arguments, exit codes, output) matters early.
Defining and calling #
log() {
echo "[$(date +%H:%M:%S)] $*" >&2
}
deploy() {
log "starting deploy to $1"
rsync -a dist/ "server:/srv/$1/"
}
deploy aospix
Definition is name() { ... } — no function keyword needed, no parentheses on parameters. Calls look like commands, because they are: functions join PATH-found commands in the namespace and even appear in type deploy.
Parameters: positional, inside #
Inside a function, $1, $2, … are the function's own arguments — they do not leak from the script's. "$@" is all of them, $# the count:
run_in_dir() {
local dir="$1"; shift
( cd "$dir" && "$@" )
}
run_in_dir /var/log tail -n 5 messages
local keeps variables inside the function — without it, a loop variable in a helper silently overwrites the caller's. The shift idiom peels the first argument so "$@" becomes "the rest".
Returning: two channels #
Bash functions return one thing officially — a numeric status, like every command:
file_exists() {
[[ -f "$1" ]]
}
if file_exists "$config"; then echo ok; fi
The function's return value is the exit code of its last command — so a bare [[ ]] is a perfectly good boolean. Data comes back the other channel: output. The caller captures it with command substitution:
current_branch() {
git rev-parse --abbrev-ref HEAD
}
branch="$(current_branch)"
Mixing the channels is the classic bug: an echo "debug..." inside a function whose output is captured will corrupt the result — send diagnostics to stderr (>&2) and data to stdout, always.
| You want | Mechanism |
|---|---|
| Success/failure | return 0 or last command's status |
| A value back | Echo it; caller uses "$(fn)" |
| Progress messages | echo ... >&2 |
| Private variables | local |
Arguments arrive via $1 and friends; structure grows from arrays. The scripting series continues.
