Парсинг аругментов в Shell#
Полезные ссылки:
Ручной разбор аргументов#
Ультимативный парсер выглядит следующим образом:
1optval() {
2 # GNU-style CLI options parser.
3 #
4 # Parse `--opt VAL` and `--opt=VAL` options.
5 # Usage: optval "$1" "$2"
6 # Sets variables:
7 # opt - option name
8 # val - option's value
9 # sft - value for shift
10
11 opt="${1%%=*}"; val="${1##*=}"; sft=1
12
13 if [ "$opt" == "$val" ]; then
14 if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
15 val="$2"; sft=2
16 else
17 unset val
18 fi
19 fi
20
21 if [ -z "$val" ]; then
22 echo "Missing argument for option $opt" >&2; exit 1
23 fi
24}
25
26# Print help if no arguments passed
27[[ "$#" == 0 ]] && { echo "Help text"; exit 1; }
28
29# Split combined short options, e.g. '-abc' to '-a' '-b' '-c'
30for args in "$@"; do
31 shift
32 case "$args" in
33 --*)
34 set -- "$@" "$args";; # save long options
35 -*)
36 args="$(echo "${args:1}" | grep -o . | xargs -I {} echo -n '-{} ')"
37 set -- "$@" $args;;
38 *)
39 set -- "$@" "$args";; # save positional arguments
40 esac
41done
42
43# Final arguments parser
44while (( "$#" )); do
45 case "$1" in
46 -h|--help) echo "Help text"; exit 0;;
47 -v|--version) echo "v1.0.0"; exit 0;;
48 -c|--config|--config=*) optval "$1" "$2"; config="$arg"; shift "$sft";;
49 --) __args+=("$@"); shift "$#";; # end of options
50 -*) echo "Error: unknown option: $1" >&2; exit 1;;
51 *) __args+=("$1"); shift;; # save positional args
52 esac
53done
Код парсера достаточно громоздкий, зато он:
обрабатывать короткие опции
-a -b
и-ab
;обрабатывает длинные опции
--config FILE
и--config=FILE
;поддерживает «end of options»
--
;сохраняет все позиционные аргументы.
POSIX getopts#
У getopts
есть неприятный ньюанс, заключающийся в том, что он умеет работать исключительно с короткими опциями. Но на самом деле не проблема научить его работать и с длинными.
1# Print help if no arguments passed
2[ "$#" -eq 0 ] && { echo "Help text"; exit 1; }
3
4# Transform long options to short ones
5for arg in "$@"; do
6 shift
7 case "$arg" in
8 --help) set -- "$@" "-h";;
9 --version) set -- "$@" "-v";;
10 *) set -- "$@" "$arg";;
11 esac
12done
13
14# Parse short options
15while getopts ":hvS" opt; do
16 case "$opt" in
17 h) echo "Help text"; exit 0;;
18 v) echo "v1.0.0"; exit 0;;
19 *) echo "Unknown option $opt" >&2; exit 1;;
20 esac
21done
22
23# Parse positional arguments from $@
24shift $((OPTIND - 1))
При использовании getopts
внутри функций надо позаботиться о том, чтобы переменная OPTIND
была объявлена локальной, иначе парсер будет вести себя непредсказуемо.
local OPTIND
Это не сработает в строгой POSIX оболочке, т.к. в ней нет команды local
.