Skip to content

Instantly share code, notes, and snippets.

@dgoguerra
Last active November 10, 2024 20:00
Show Gist options
  • Save dgoguerra/9206418 to your computer and use it in GitHub Desktop.
Save dgoguerra/9206418 to your computer and use it in GitHub Desktop.
Manual alternative to getopt in bash scripts, supporting short and long options
#!/usr/bin/env bash
# File name
readonly PROGNAME=$(basename $0)
# File name, without the extension
readonly PROGBASENAME=${PROGNAME%.*}
# File directory
readonly PROGDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# Arguments
readonly ARGS="$@"
# Arguments number
readonly ARGNUM="$#"
usage() {
echo "Script description"
echo
echo "Usage: $PROGNAME -i <file> -o <file> [options]..."
echo
echo "Options:"
echo
echo " -h, --help"
echo " This help text."
echo
echo " -i <file>, --input <file>"
echo " Input file. If \"-\", stdin will be used instead."
echo
echo " -o <file>, --output <file>"
echo " Output file."
echo
echo " --"
echo " Do not interpret any more arguments as options."
echo
}
while [ "$#" -gt 0 ]
do
case "$1" in
-h|--help)
usage
exit 0
;;
-i|--input)
input="$2"
# Jump over <file>, in case "-" is a valid input file
# (keyword to standard input). Jumping here prevents reaching
# "-*)" case when parsing <file>
shift
;;
-o|--output)
output="$2"
;;
--)
break
;;
-*)
echo "Invalid option '$1'. Use --help to see the valid options" >&2
exit 1
;;
# an option argument, continue
*) ;;
esac
shift
done
# script content!
@derekpk
Copy link

derekpk commented Aug 28, 2015

very nice, exactly what I was looking for.

@seropian
Copy link

+1 :) simple and effective

@brainfucksec
Copy link

brainfucksec commented Nov 1, 2017

Thanks for this solution dgoguerra.
I added this code at the end:

*)
    echo "Invalid option '$1'. Use --help to see the valid options" >&2
    exit 1
    ;;
    esac
    shift

@unfor19
Copy link

unfor19 commented Aug 8, 2020

Thanks for sharing! I wrote a script which helps to parse command line arguments in Bash, it's called bargs - https://github.com/unfor19/bargs , it's based on the same logic above, but simpler to manage

@YevheniiPokhvalii
Copy link

Thanks! That what I was looking for as a replacement for getopts.

My points here:
getopts is inconsistent when sourcing a script in different shells.
getopts relies on the OPTIND variable (OPTIND=1 by default) and that variable works differently in bash and zsh.
While getopts can be fixed in bash by setting OPTIND=1, zsh also requires addition manipulations like a shell replacement with exec zsh.

@fcojperez
Copy link

Pretty cool👍👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment