Best way to parse command line args in Bash?

旧巷老猫 提交于 2019-11-27 08:28:46

I find the use of getopt to be the easiest. It provides correct handling of arguments which is tricky otherwise. For example, getopt will know how to handle arguments to a long option specified on the command line as --arg=option or --arg option.

What is useful in parsing any input passed to a shell script is the use of the "$@" variables. See the bash man page for how this differs from $@. It ensures that you can process arguments that include spaces.

Here's an example of how I might write s script to parse some simple command line arguments:

#!/bin/bash

args=$(getopt -l "searchpath:" -o "s:h" -- "$@")

eval set -- "$args"

while [ $# -ge 1 ]; do
        case "$1" in
                --)
                    # No more options left.
                    shift
                    break
                   ;;
                -s|--searchpath)
                        searchpath="$2"
                        shift
                        ;;
                -h)
                        echo "Display some help"
                        exit 0
                        ;;
        esac

        shift
done

echo "searchpath: $searchpath"
echo "remaining args: $*"

And used like this to show that spaces and quotes are preserved:

user@machine:~/bin$ ./getopt_test --searchpath "File with spaces and \"quotes\"."
searchpath: File with spaces and "quotes".
remaining args: other args

Some basic information about the use of getopt can be found here

If you want to avoid using getopt you can use this nice quick approach:
- Defining help with all options as ## comments (customise as you wish);
- Define for each option a function with same name;
- Copy the last five lines of this script to your script (the magic).

Example: log.sh

#!/bin/sh
## $PROG 1.0 - Print logs [2017-10-01]
## Compatible with bash and dash/POSIX
## 
## Usage: $PROG [OPTION...] [COMMAND]...
## Options:
##   -i, --log-info         Set log level to info (default)
##   -q, --log-quiet        Set log level to quiet
##   -l, --log MESSAGE      Log a message
## Commands:
##   -h, --help             Displays this help and exists
##   -v, --version          Displays output version and exists
## Examples:
##   $PROG -i myscrip-simple.sh > myscript-full.sh
##   $PROG -r myscrip-full.sh   > myscript-simple.sh
PROG=${0##*/}
LOG=info
die() { echo $@ >&2; exit 2; }

log_info() {
  LOG=info
}
log_quiet() {
  LOG=quiet
}
log() {
  [ $LOG = info ] && echo "$1"; return 1 ## number of args used
}
help() {
  grep "^##" "$0" | sed -e "s/^...//" -e "s/\$PROG/$PROG/g"; exit 0
}
version() {
  help | head -1
}

[ $# = 0 ] && help
while [ $# -gt 0 ]; do
  CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g")
  if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi
  shift; eval "$CMD" $@ || shift $? 2> /dev/null
done

Testing:

./log.sh --log yep --log-quiet -l nop -i -l yes will produce:

yep
yes

By the way: It's compatible with POSIX!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!