I asked ChatGPT to "Write me a Bash script that accepts short, long, and positional arguments" and it came up with the following:
#!/bin/bash
# Define short options
options=":s:l:"
# Define long options
long_options=("short-option:" "long-option:")
# Parse options and arguments
while getopts "$options" opt; do
case $opt in
s)
short_opt_arg="$OPTARG"
;;
l)
long_opt_arg="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
# Shift parsed options to access positional arguments
shift $((OPTIND-1))
# Display parsed options and positional arguments
echo "Short option argument: $short_opt_arg"
echo "Long option argument: $long_opt_arg"
echo "Positional arguments: $@"
It may look impressive but the code is wrong because getopts
does not support long option names. The usage ChatGPT suggested is shown below and if you save the code above in script.sh
and try to run the example, it'll return an error.
./script.sh -s value1 --long-option=value2 arg1 arg2 arg3
Invalid option: --
One way to accept short, long, and positional arguments in a Bash script is to use GNU getopt
(without the s). Here's a template:
#!/usr/bin/env bash
#
# Adapted from https://www.shellscript.sh/examples/getopt/
#
set -euo pipefail
alpha=unset
beta=unset
gamma=unset
delta=unset
usage(){
>&2 cat << EOF
Usage: $0
[ -a | --alpha ]
[ -b | --beta ]
[ -g | --gamma input ]
[ -d | --delta input ]
<infile> [infiles]
EOF
exit 1
}
args=$(getopt -a -o abhc:d: --long alpha,beta,help,gamma:,delta: -- "$@")
if [[ $? -gt 0 ]]; then
usage
fi
eval set -- ${args}
while :
do
case $1 in
-a | --alpha) alpha=1 ; shift ;;
-b | --beta) beta=1 ; shift ;;
-h | --help) usage ; shift ;;
-c | --gamma) gamma=$2 ; shift 2 ;;
-d | --delta) delta=$2 ; shift 2 ;;
# -- means the end of the arguments; drop this, and break out of the while loop
--) shift; break ;;
*) >&2 echo Unsupported option: $1
usage ;;
esac
done
if [[ $# -eq 0 ]]; then
usage
fi
>&2 echo "alpha : ${alpha}"
>&2 echo "beta : ${beta} "
>&2 echo "gamma : ${gamma}"
>&2 echo "delta : ${delta}"
>&2 echo "Parameters remaining are: $@"
exit 0
If you run the script without any arguments/options, you'll get the usage:
./getopt.sh
Usage: ./getopt.sh
[ -a | --alpha ]
[ -b | --beta ]
[ -g | --gamma input ]
[ -d | --delta input ]
<infile> [infiles]
The -a
or --alpha
and -b
or --beta
are switches; if you specify them they become 1. -g
or --gamma
and -d
or --delta
accept an input. Positional inputs are provided after the optional parameters. Below is an example:
./getopt.sh -a --beta -g gamma_input --delta delta_input test.txt test2.txt
# alpha : 1
# beta : 1
# gamma : gamma_input
# delta : delta_input
# Parameters remaining are: test.txt test2.txt
How does the script work? It all relies on the following line of code:
args=$(getopt -a -o abhc:d: --long alpha,beta,help,gamma:,delta: -- "$@")
$@
is a special Bash variable that contains all the command line arguments passed to the script. In the example above, $@
would contain:
-a --beta -g gamma_input --delta delta_input test.txt test2.txt
The command line arguments are provided to getopt
along with the short (-o
) and long (--long
) options to be recognised. The -a
argument to getopt
allows us to specify long options with a single dash, so the following works as well.
./getopt.sh -a -beta -g gamma_input -delta delta_input test.txt test2.txt
# alpha : 1
# beta : 1
# gamma : gamma_input
# delta : delta_input
# Parameters remaining are: test.txt test2.txt
The rest of the code simply parses the output of getopt
(with a Bash case statement), which is stored in the variable args
and contains the following for our example:
-a --beta --gamma 'gamma_input' --delta 'delta_input' -- 'test.txt' 'test2.txt'
You may have used command line tools in the past where you included a double-dash (--
). This is typically used to demarcate the end of the optional parameters. In the Bash script above, when --
is encountered the while loop breaks out (exits) and what is left in the stack ($@
) are the positional arguments.
So there you have it: +1 to humanity.

This work is licensed under a Creative Commons
Attribution 4.0 International License.