Bash: Parse Options And Non-Options With Getopts

Parsing script or function options and non-option arguments is easy in Bash with getopts but there are some catches, such as the need to reset OPTIND. We will se how to do it using getopts, shift, and case.

The code below will parse the function arguments and remove them so that $1 will refer to the first non-option argument (i.e. not starting with -). You would invoke it f.ex. as  latest_recur -x Hello -a '*.txt'.

# Find the latest files under the current dir, recursively; options:
# -a list all, not only 30 latest
#  - pattern passed to find's -name; ex.: "*.log.processed"
function latest_recur {
   local show_all=
   while getopts "ax:" opt; do
      case $opt in
         a) show_all=yes ;;
         x) echo "You said: $OPTARG" ;;
         \?) echo "Invalid option: -$OPTARG" >&2; return 1;;
   shift $((OPTIND-1))

if [ -z "$1" ]; then NAME_ARG=""; else NAME_ARG="-name $1"; fi find -type f $NAME_ARG | xargs --no-run-if-empty stat --format '%Y :%y %n' | sort -nr | if [ -z "$show_all" ]; then head -n 30 -; else cat -; fi }
  • #5, #9 the variable used to store the flag must be defined/reset first
  • #6 OPTIND is a global variable pointing to the next argument that getopts should parse; you must reset it manually (otherwise the next call to the function will ignore its arguments)
  • #7 getopts parses one by one all the supported options (a, x here) and stores them into $opt;
  • #10, #11 the value passed to the option (Hello, *.txt) is stored into the variable OPTARG
  • #14 we must manually shift away the processed option arguments so that the first non-option argument ('*.txt') will become argument number 1 as you can see at #16; OPTIND is set by getopts
Getopts can do quite a lot. It supports short options with or without arguments such as "-lht", "-l -h -t", "-l -I '*.swp'". It can also report/ignore unknown arguments etc., see its brief documentation and this small getopts tutorial. Briefly said, getopts takes opstring and varname; opstring is a list of letters optionally followed by ':' to indicate that that flag requires a value; varname is the name of the variable to store the flag name into. If you put : in front of the opstring (":ax:") then it will not complain about unknown options or missing arguments for options that require them.

Copyright © 2024 Jakub Holý
Powered by Cryogen
Theme by KingMob