Advanced Bash Scripting

Special Shell Variables

Zero

In Bash scripting, the special parameter $0 holds the name (and path) used to invoke the script. Understanding and manipulating $0 lets you:

  1. Retrieve the script’s invoked name or full path
  2. Derive the absolute directory where the script resides

Below, we explore each technique with practical examples and patterns for robust, user-friendly scripts.


Table of Contents

  1. Getting the Invoked Script Name
  2. Extracting Only the Basename
  3. Dynamic Usage Messages with SCRIPT_NAME
  4. Graceful Exits via a terminate Helper
  5. Resolving the Script’s Directory (WORK_DIR)
  6. Quick Reference Table
  7. Links and References

1. Getting the Invoked Script Name

By default, $0 prints exactly how the script was called:

#!/usr/bin/env bash
echo "$0"

Save this as show-zero.sh and run:

$ ./show-zero.sh
./show-zero.sh

$ # If on your PATH:
$ show-zero.sh
/usr/local/bin/show-zero.sh

2. Extracting Only the Basename

To obtain just the filename (dropping any leading directories), use shell parameter expansion:

#!/usr/bin/env bash
readonly SCRIPT_NAME=${0##*/}
echo "${SCRIPT_NAME}"

Running:

$ ./show-zero.sh
show-zero.sh

Here ${0##*/} strips everything up to the last slash.


3. Dynamic Usage Messages with SCRIPT_NAME

Embedding the script’s basename in help text ensures accuracy, even if the file is renamed:

#!/usr/bin/env bash
readonly SCRIPT_NAME=${0##*/}

usage() {
  cat <<USAGE
Usage: ${SCRIPT_NAME} <name>

Greet a user by name.

Arguments:
  name       The name to greet.

Options:
  -h, --help Show this help message and exit.
USAGE
}

# Show usage
usage

Example output:

$ ./show-zero.sh
Usage: show-zero.sh <name>

Greet a user by name.

Arguments:
  name       The name to greet.

Options:
  -h, --help Show this help message and exit.

4. Graceful Exits via a terminate Helper

Centralize error reporting and custom exit codes:

#!/usr/bin/env bash
readonly SCRIPT_NAME=${0##*/}
readonly ERR_MISSING_ARG=155

usage() {
  cat <<USAGE
Usage: ${SCRIPT_NAME} <name>

Greet a user by name.

Options:
  -h, --help Show this help message and exit.
USAGE
}

terminate() {
  echo "Error: ${1}" >&2
  exit "${2:-1}"
}

# Argument count check
if [[ $# -ne 1 ]]; then
  usage
  terminate "Missing argument" "$ERR_MISSING_ARG"
fi

# Help flag
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
  usage
  exit 0
fi

name="$1"
echo "Hello, ${name}! Welcome!"
exit 0

Example runs:

$ ./greet.sh
Usage: greet.sh <name>
Error: Missing argument
$ echo $?
155

$ ./greet.sh --help
Usage: greet.sh <name>
$ echo $?
0

Note

For more advanced flag parsing, consider using getopts to handle short and long options.


5. Resolving the Script’s Directory (WORK_DIR)

Hard-coding relative paths can break when you run scripts from different locations. Instead, compute the script’s own directory:

#!/usr/bin/env bash
readonly WORK_DIR=$(dirname "$(readlink -f "$0")")
  • readlink -f "$0" returns the script’s canonical absolute path (following symlinks).
  • dirname extracts the parent directory.

Now you can reliably reference files relative to the script’s location:

cd "${WORK_DIR}/../assets"
cd "${WORK_DIR}/subdir"
# ...other tasks

Warning

On macOS, readlink -f may not be available. Use brew install coreutils or alternative methods (realpath).


6. Quick Reference Table

FeaturePurposeExample
$0How the script was invokedecho "$0"
${0##*/}Basename of the scriptSCRIPT_NAME=${0##*/}
Dynamic heredoc usage messagesEmbed SCRIPT_NAME in help textcat <<USAGE…
terminate()Standardize error output and exit codesterminate "message" 42
readlink -f + dirnameCompute absolute script directory (WORK_DIR)WORK_DIR=$(dirname "$(readlink -f "$0")")"

These patterns make your Bash scripts more predictable, portable, and user-friendly—leveraging $0 effectively is a key skill for any shell scripter.

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
pid