Using getopts to process long and short command line options

后端 未结 30 1962
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-21 22:52

I wish to have long and short forms of command line options invoked using my shell script.

I know that getopts can be used, but like in Perl, I have not

30条回答
  •  攒了一身酷
    2020-11-21 23:06

    I wanted something without external dependencies, with strict bash support (-u), and I needed it to work on even the older bash versions. This handles various types of params:

    • short bools (-h)
    • short options (-i "image.jpg")
    • long bools (--help)
    • equals options (--file="filename.ext")
    • space options (--file "filename.ext")
    • concatinated bools (-hvm)

    Just insert the following at the top of your script:

    # Check if a list of params contains a specific param
    # usage: if _param_variant "h|?|help p|path f|file long-thing t|test-thing" "file" ; then ...
    # the global variable $key is updated to the long notation (last entry in the pipe delineated list, if applicable)
    _param_variant() {
      for param in $1 ; do
        local variants=${param//\|/ }
        for variant in $variants ; do
          if [[ "$variant" = "$2" ]] ; then
            # Update the key to match the long version
            local arr=(${param//\|/ })
            let last=${#arr[@]}-1
            key="${arr[$last]}"
            return 0
          fi
        done
      done
      return 1
    }
    
    # Get input parameters in short or long notation, with no dependencies beyond bash
    # usage:
    #     # First, set your defaults
    #     param_help=false
    #     param_path="."
    #     param_file=false
    #     param_image=false
    #     param_image_lossy=true
    #     # Define allowed parameters
    #     allowed_params="h|?|help p|path f|file i|image image-lossy"
    #     # Get parameters from the arguments provided
    #     _get_params $*
    #
    # Parameters will be converted into safe variable names like:
    #     param_help,
    #     param_path,
    #     param_file,
    #     param_image,
    #     param_image_lossy
    #
    # Parameters without a value like "-h" or "--help" will be treated as
    # boolean, and will be set as param_help=true
    #
    # Parameters can accept values in the various typical ways:
    #     -i "path/goes/here"
    #     --image "path/goes/here"
    #     --image="path/goes/here"
    #     --image=path/goes/here
    # These would all result in effectively the same thing:
    #     param_image="path/goes/here"
    #
    # Concatinated short parameters (boolean) are also supported
    #     -vhm is the same as -v -h -m
    _get_params(){
    
      local param_pair
      local key
      local value
      local shift_count
    
      while : ; do
        # Ensure we have a valid param. Allows this to work even in -u mode.
        if [[ $# == 0 || -z $1 ]] ; then
          break
        fi
    
        # Split the argument if it contains "="
        param_pair=(${1//=/ })
        # Remove preceeding dashes
        key="${param_pair[0]#--}"
    
        # Check for concatinated boolean short parameters.
        local nodash="${key#-}"
        local breakout=false
        if [[ "$nodash" != "$key" && ${#nodash} -gt 1 ]]; then
          # Extrapolate multiple boolean keys in single dash notation. ie. "-vmh" should translate to: "-v -m -h"
          local short_param_count=${#nodash}
          let new_arg_count=$#+$short_param_count-1
          local new_args=""
          # $str_pos is the current position in the short param string $nodash
          for (( str_pos=0; str_pos&2
        fi
        shift $shift_count
      done
    }
    

    And use it like so:

    # Assign defaults for parameters
    param_help=false
    param_path=$(pwd)
    param_file=false
    param_image=true
    param_image_lossy=true
    param_image_lossy_quality=85
    
    # Define the params we will allow
    allowed_params="h|?|help p|path f|file i|image image-lossy image-lossy-quality"
    
    # Get the params from arguments provided
    _get_params $*
    

提交回复
热议问题