Script foundations

Read positional arguments

Accept a required path argument, show usage, and distinguish the script name from user values.

When you run ./check-dir /var/www, Bash stores the script name in $0 and arguments in $1, $2, and so on. $# reports how many arguments were supplied. These are the positional parameters, and they are how a script receives input without prompting anyone.

Require an argument

A script that needs input should check for it up front and explain itself when the caller gets it wrong. Create check-dir:

#!/usr/bin/env bash

if (( $# != 1 )); then
  printf 'usage: %s DIRECTORY\n' "$0" >&2
  exit 2
fi

directory=$1
printf 'checking %s\n' "$directory"

(( ... )) is arithmetic evaluation, the natural way to compare numbers like $#. The usage message goes to standard error with >&2, not standard output. Error text must never mix with real output that another program might consume. Status 2 is the conventional “you called me wrong” code. grep and many other tools use it the same way.

Copying $1 into a named variable is a small kindness to future readers. Twenty lines down, "$directory" explains itself. "$1" does not.

Verify all three cases

Run it with zero, one, and two arguments:

./check-dir
# usage: ./check-dir DIRECTORY

./check-dir /var/www
# checking /var/www

./check-dir /var/www /tmp
# usage: ./check-dir DIRECTORY

Check the status too: echo $? prints 2 after the invalid calls and 0 after the good one. Invalid usage should print to standard error and return status 2 every time, because schedulers and other scripts act on the number, not the text.

Count is not meaning

The realistic mistake is stopping here. One argument can still name a missing or unsafe path:

if [[ ! -d $directory ]]; then
  printf '%s is not a directory\n' "$directory" >&2
  exit 1
fi

Validate meaning after count. A script that accepts any string as its “log directory” and marches on will fail later, somewhere far less obvious than line three.

One more parameter worth knowing now: "$@" expands to all arguments, each preserved as its own word. We put it to work in the lesson on loops.

Lesson completed