Reading — step 1 of 5
Learn
Functions
Bash functions are miniature scripts living inside your script: they take arguments the same way, return exit statuses the same way, and "return" data the way commands do — by printing it. Embrace the command-ness and they're simple; fight it and they're baffling.
Defining and calling
greet() {
echo "Hello, $1"
}
greet "Ada" # call = invoke like a command. No parentheses!
greet "Grace"
Arguments arrive as positional parameters: $1, $2, … plus $# (how many) and "$@" (all of them, properly quoted — the only correct way to forward arguments). Nothing is declared in the parentheses — they're purely syntax marking "this is a function."
Getting data OUT: print it
Here's the mental flip. return in bash sets the exit status (0–255, success/failure) — it cannot return data. Data leaves a function on stdout, and the caller captures it with command substitution:
square() {
echo "$(( $1 * $1 ))"
}
result=$(square 7) # capture the function's output
echo "$result" # 49
$( … ) runs a command (or function — same thing!) and substitutes its output. This is exactly how you capture $(date) or $(wc -l < file); functions earn no special treatment because they are commands. Corollary that bites everyone once: anything a function prints becomes part of its "return value" — a stray debug echo inside corrupts the captured result. (Debug prints belong on stderr: echo "debug" >&2 — pipes lesson formalizes this.)
return still matters for its real job — signaling success/failure:
is_even() {
(( $1 % 2 == 0 )) # arithmetic test's status becomes the function's status
}
if is_even 4; then echo "even"; fi # functions as conditions — very bash
local: the keyword that keeps you sane
Variables in bash are global by default — even inside functions:
count_things() {
n=$(( $1 + 1 )) # silently overwrites any outer $n !
}
count_things 5
echo "$n" # 6 — your function leaked
The fix is local n=$(( $1 + 1 )) — scoped to the function, gone at return. The professional rule has no exceptions worth learning: every variable inside a function gets local. It's the cheapest bug insurance in the language; unscoped helper variables colliding across functions produce the kind of spooky, order-dependent bugs that take evenings.
Your exercise: Square It
A square function plus read/call/print plumbing:
square() {
local n=$1
echo "$(( n * n ))"
}
read x
square "$x"
Note the last line: since square prints its answer, calling it IS printing — no capture needed when the output goes straight to the grader (capture with $( ) when you need the value for further work). The graded habits: local on the function's variable, quoted "$x" at the call, logic in the function and I/O outside — the same separation as every other track, expressed in bash's native idiom of small programs calling smaller ones.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…