Skip to content

Chapter 5 of 8

Functions, Sourcing, and Command-Line Arguments

Functions are defined in Bash with name() { commands; } or with the keyword form function name { commands; }. The body of a function executes in the same shell environment as the caller — there is no automatic local scope — so variables assigned inside a function leak into the surrounding scope unless they are declared with local foo=bar, which hides any global of the same name for the duration of the function. Arguments are passed as positional parameters $1, \(2, ..., exactly as in a script, and they are forwarded correctly with "\)@". From Bash 4.3 onward, arrays may be passed by reference using declare -n refname=array. A function exits with return N (where N defaults to the status of the last command), in contrast to exit N, which terminates the entire script — a subtle but important distinction.

Two related mechanisms for modularization are source script.sh (or its POSIX alias . script.sh) and the getopts builtin. source executes a file in the current shell, so any variable assignments or directory changes made by that file persist in the caller — this is why source is the standard way to load a configuration file of Bash variables. There is no separate include mechanism in Bash: modules are sourced, and there is no harm in doing so because source is precisely identical to the dot operator. getopts, by contrast, parses short command-line options such as -a or -b value from a script's own argument list. The typical idiom is while getopts "ab:c" opt; do case \(opt in ...) esac; done, where the option string declares which letters take arguments (those followed by :). The argument to the current option is in \)OPTARG, and $OPTIND points past the consumed options; the usual cleanup is shift $((OPTIND-1)) after the loop, so that "$@" still contains the remaining positional arguments. Before calling any external tool, the robust check for its presence is command -v cmd >/dev/null 2>&1, not the legacy which.

A subtle issue worth knowing is that strict mode does not protect you from a misleading cd. set -e exits when a later command fails for whatever reason, which can hide a failed cd that was supposed to be the cause. The defensive idiom is cd /path || exit 1 or pushd /path || exit to make the directory change itself visible to error handling. The : builtin is a useful no-op that returns 0 and discards its arguments; it is handy as a placeholder in empty function bodies and is the canonical left-hand side of parameter expansion tricks such as : "${VAR:=default}".

All chapters
  1. 1Foundations of Bash Scripting
  2. 2Variables, Expansion, Quoting, and Strict Mode
  3. 3Conditionals and Tests
  4. 4Loops and Iteration
  5. 5Functions, Sourcing, and Command-Line Arguments
  6. 6Arrays, Strings, Substitutions, and Arithmetic
  7. 7Input/Output, Redirection, and File Handling
  8. 8Process Control, Scheduling, and Robust Practices

Drill it

Reading is not remembering. These come from the Bash Scripting For Automation deck:

Q

What is Bash?

Bash (Bourne Again SHell) is a Unix shell and command language written as a free software replacement for the Bourne shell (sh). It is the default login shell o...

Q

What file extension is conventionally used for Bash scripts?

.sh. While not strictly required for execution, .sh signals intent and lets tooling treat the file as a shell script.

Q

What must the first line of an executable Bash script be?

A shebang line, e.g. #!/usr/bin/env bash or #!/bin/bash, which tells the kernel which interpreter to invoke.

Q

What command makes a script file executable?

chmod +x script.sh (or chmod 755 script.sh).