Best way to parse command line args in Bash?

前端 未结 2 1275
半阙折子戏
半阙折子戏 2020-11-30 07:11

After several days of research, I still can\'t figure out the best method for parsing cmdline args in a .sh script. According to my references the getopts cmd is the way to

相关标签:
2条回答
  • 2020-11-30 07:30

    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 script: 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#--}(?:[= ])" log.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

    Running this command:

    ./log.sh --log yep --log-quiet -l nop -i -l yes
    

    Produces this output:

    yep
    yes
    

    By the way: It's compatible with posix!

    0 讨论(0)
  • 2020-11-30 07:39

    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

    0 讨论(0)
提交回复
热议问题