DevOps Peach

Linux · Bash Scripting · Lesson 5 of 5

Functions, arguments, and special parameters

Isolate reusable logic and pass data through arguments or stdout.

Practice interactively →

Defining functions

A function groups commands under a name. Both greet() { ...; } and function greet { ...; } work in Bash; the first form is also valid in sh. A function must be defined before the line that calls it.

A function runs in the current shell, so use local to avoid overwriting a global variable. return supplies only an exit status from 0 through 255; to produce text, print to stdout and capture it with command substitution.

greet() { local who=${1:-World}; printf 'hello %s\n' "$who"; }
message=$(greet World)

${1:-World} gives the argument a default when the caller passes nothing. exit inside a function ends the whole script, not just the function.

flowchart LR
  CALL["backup /etc /srv<br/>call"] --> FN["backup()<br/>local dir=$1"]
  FN --> ARGS["$1 $2, $@, $#<br/>arguments"]
  FN --> OUT["echo result<br/>stdout"]
  FN --> RC["return 0/1<br/>status"]
  TRAP["trap cleanup EXIT"] -.-> FN
  %% step CALL: You call a function like a command, with arguments after its name.
  %% step FN: Inside, local keeps variables from leaking into the rest of the script.
  %% step ARGS: $1, $2 hold the arguments, "$@" all of them, $# how many.
  %% step OUT: To return data, print it and capture it with $( ).
  %% step RC: return sets only the exit status, 0 to 255.
  %% step TRAP: trap runs cleanup code when the script exits, even on error.

Special parameters

Parameter Meaning
$0 Script or shell name
$1 First argument
$# Argument count
"$@" All arguments, preserving boundaries
$? Status of the most recent command
$! PID of the most recent background pipeline
$$ Current shell PID

Inside a function, $1 and $# refer to the function's own arguments, not the script's. When forwarding arguments in a loop, use for arg in "$@"; quoted $* joins everything into one word. Another command replaces $?, so capture it immediately as status=$?.

Parsing options

shift removes $1 and moves the remaining arguments down, which is useful in a while plus case parser. Check that enough arguments exist before shifting multiple positions. For short flags, the builtin getopts does the parsing:

while getopts "e:v" opt; do
  case $opt in
    e) env=$OPTARG ;;
    v) verbose=1 ;;
    *) usage; exit 1 ;;
  esac
done

A usage() function that prints the expected syntax and exits with status 1 makes a script friendlier when it is called wrongly.

Cleanup and reuse

trap cleanup EXIT calls a cleanup function when the script ends for any reason, which is the usual way to delete temporary files. Functions shared by several scripts can live in one file such as lib.sh and be loaded with source lib.sh. Keep each function small and named for what it does, such as backup_db or check_disk.

Practice interactively →