Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I parse long-form arguments in shell?

Tags:

bash

shell

sh

Everything I see uses getopt or the slightly-fancier getopts which only supports one-character options (e.g., -h but not --help). I want to do fancy long options.

like image 814
Ian Bicking Avatar asked Feb 14 '12 03:02

Ian Bicking


People also ask

How do you parse arguments in bash?

The shift keyword takes an additional argument of how many positions of the arguments to move the cursor to. To parse the next argument, the shift command has a number 2 assigned to it, which would switch to the next argument. Notice how the script exited when it encountered a double hyphen ( -- ).

How do you pass runtime arguments in shell script?

Using arguments Inside the script, we can use the $ symbol followed by the integer to access the arguments passed. For example, $1 , $2 , and so on. The $0 will contain the script name.

How do you read arguments in a shell program?

The special character $# stores the total number of arguments. We also have $@ and $* as wildcard characters which are used to denote all the arguments. We use $$ to find the process ID of the current shell script, while $? can be used to print the exit code for our script.

How do I parse a command-line in bash?

To parse short command-line options, we can use bash's built-in function getopts. It parses positional parameters as options.


2 Answers

I've done something like this:

_setArgs(){
  while [ "${1:-}" != "" ]; do
    case "$1" in
      "-c" | "--configFile")
        shift
        configFile=$1
        ;;
      "-f" | "--forceUpdate")
        forceUpdate=true
        ;;
      "-r" | "--forceRetry")
        forceRetry=true
        ;;
    esac
    shift
  done
}

As you can see, this supports both the single-character and the longer options nicely. It allows for values to be associated with each argument, as in the case of --configFile. It's also quite extensible, with no artificial limitations as to what options can be configured, etc.

As included above, the "${1:-}" prevents an "unbound variable" error when running in bash "strict" mode (set -euo pipefail).

like image 118
ziesemer Avatar answered Oct 09 '22 02:10

ziesemer


Assuming that you "want to do fancy long options" regardless of the tool, just go with getopt (getopts seems to be mainly used when portability is crucial). Here's an example of about the maximum complexity that you'll get:

params="$(getopt -o e:hv -l exclude:,help,verbose --name "$(basename "$0")" -- "$@")"

if [ $? -ne 0 ]
then
    usage
fi

eval set -- "$params"
unset params

while true
do
    case $1 in
        -e|--exclude)
            excludes+=("$2")
            shift 2
            ;;
        -h|--help)
            usage
            ;;
        -v|--verbose)
            verbose='--verbose'
            shift
            ;;
        --)
            shift
            break
            ;;
        *)
            usage
            ;;
    esac
done

With this code, you can specify -e/--exclude more than once, and ${excludes[@]} will contain all of the given excludes. After processing (-- is always present) anything remaining is stored in $@.

like image 25
l0b0 Avatar answered Oct 09 '22 02:10

l0b0