Skip to content
Lesson 8 of 14

Step 1 of 5 · Reading · ~3 min

Learn

Functions and Pipes

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

The starter has the plumbing -- a function stub, the read, and the call. Your job is the body.

Remember where the answer has to go. return cannot hand back a number; data leaves a bash function on stdout. So the body prints, and because the call site is the last line of the script, that print IS the program's output -- no capture needed. (Capture with $( ) when you need the value for more work.)

The graded habits: local on the function's own variable, quoted "$x" at the call site, and the arithmetic done inside an arithmetic context -- a body that echoes "(($1*$1))" in quotes prints those characters, which is the single most common wrong answer in this exercise's history. Logic inside the function, I/O outside it: the same separation as every other track, in bash's native idiom of small programs calling smaller ones.

Up nextPipes and RedirectionFunctions and Pipes

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…