📜 ⬆️ ⬇️

bash script with support for long (gnu-style) options

At first glance, the trivial task appeared: to write a script with various options at startup. Suppose you need to handle only two options: name and dir. And the task is really trivial, provided that our options are short. But if there is a burning desire to use long options, then write it is gone: getopts, which was planned to be used initially, is not suitable for bash at all.

Although in ksh everything works with a bang:
#!/bin/ksh while getopts "f(file):s(server):" flag do echo "$flag" $OPTIND $OPTARG done 

But we have a bash, so sadly sigh and try to get out of this situation.
On the one hand, the parse-independent parsing is attractive, but too boring and uninteresting: every time you need to think about handling errors, exceptions and many other things. And I don’t want to reinvent the wheel every time I write such a script.
 #!/bin/bash while true; do case "$1" in -n | --name ) echo NAME="$2"; shift 2;; -d | --dir ) echo DIR="$2"; shift 2;; esac done 

You can try using getopts with a small hack to support long names:
 #!/bin/bash while getopts ":n:d:-:" OPTION; do case "$OPTION" in -) case "$OPTARG" in name) echo LONG_NAME="${!OPTIND}";; dir) echo LONG_DIR="${!OPTIND}" ;; esac;; n) echo SHORT_NAME="$OPTARG" ;; d) echo SHORT_DIR="$OPTARG" ;; esac done 

But to call such a decision a worker, the language does not turn: at the same time only one long option is supported (the first one specified in the parameters), the second one will be ignored.

We complain that getopts_long has not yet been stuck in bash, but Google suggests that you can do it yourself: download the getopts_long function and include it in our script:
 #!/bin/bash . getopts_long while getopts_long :d:n::vh opt \ name required_argument \ dir required_argument \ help 0 "" "$@" do case "$opt" in n|name) echo NAME="$OPTLARG";; d|dir) echo DIR="$OPTLARG";; help 0 "" "$@" esac done 

It would seem that this is happiness, but an even more elegant solution was found: a more advanced shflags library, which, in addition to parsing options, can also check values. Strings, logical variables, integers, non-integers are distinguished (in fact, they are strings, because the shell does not have the concept of non-integers, but there is a check for correctness of the format. This is determined by specifying variables via DEFINE_string | _boolean | _float | _integer and even independently calls variables for options according to the long option name, also supports a bunch of different shells (sh, bash, dash, ksh, zsh). Beauty and only. You can find more information about the buns in the library itself. There you can find detailed help information. :
 #!/bin/bash . ./shflags DEFINE_string 'name' 'world' 'comment for name' 'n' DEFINE_string 'dir' 'dir' 'comment for dir' 'd' FLAGS "$@" || exit 1 eval set -- "${FLAGS_ARGV}" echo "Name is ${FLAGS_name} and dir is ${FLAGS_dir}" 

However, in this solution there is a fly in the ointment: the library uses getopt for parsing options, and a bent getopt, as they say on the Internet, does not support long options. So there may be compatibility issues.

')

Source: https://habr.com/ru/post/133860/


All Articles