Functions

Bash · Practical · 12 min

Functions keep scripts readable and testable instead of one long stream of commands.

Define a function with name() { commands; } and call it like any command: name arg1 arg2. Inside, the arguments are $1, $2, $# and "$@", just like a script; $0 still names the script.

Variables are global by default, so a function that sets i clobbers the caller's i. Declare working variables with local (it is dynamically scoped: functions called from yours see them too).

Functions "return" in two ways:

  • Status: return N (0-255), or implicitly the status of the last command. This is for success/failure, so a function like is_even can be used directly in if.
  • Data: print it to stdout and capture with result=$(myfunc). Send logs and errors to stderr (>&2) so they do not pollute captured output.

Capturing with $( ) runs the function in a subshell, so variable changes inside are lost; if you need to set a caller's variable, use a global or a name reference (local -n ref=$1, bash 4.3+).

Define functions before calling them (bash reads scripts top to bottom). A common layout is: settings, functions, then a main "$@" call at the very end, which also keeps a half-downloaded script from running partially.

Example

log() { printf '[%s] %s\n' "$(date +%T)" "$*" >&2; }
max() {
  local a=$1 b=$2            # local: invisible outside the function
  if (( a > b )); then echo "$a"; else echo "$b"; fi
}
is_even() { (( $1 % 2 == 0 )); }    # status of last command = result
set_var() { local -n ref=$1; ref=$2; }   # nameref: write caller's variable
main() {
  log "starting"             # [12:00:00] starting  (on stderr)
  local biggest
  biggest=$(max 4 9)         # data comes back via stdout
  echo "max=$biggest"        # max=9
  if is_even 10; then echo "10 is even"; fi   # 10 is even
  is_even 7 || echo "7 is odd"                # 7 is odd
  set_var color blue; echo "color=$color"     # color=blue
}
main "$@"

Remember

  • name() { ...; } with $1, $2, "$@" for arguments
  • Use local for every working variable
  • return is a status; output data on stdout and capture with $( )

Watch out for

  • Using return "$value" to return data: it is a 0-255 status code, not a value.

Check yourself

  1. A function sets `count=5` without local. What happens to a global count?
  2. How should a function hand a string result to its caller?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.gnu.org/software/bash/manual/bash.html#Shell-Functions