-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
advanced.sh
executable file
·143 lines (126 loc) · 3.59 KB
/
advanced.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/bin/bash
# shellcheck disable=SC2153
set -eu
VERSION=0.1
BLOOD_TYPES='A | B | O | AB'
PROG=${0##*/}
: "${LANG:=C}"
# shellcheck disable=SC1083,SC2016,SC2145
parser_definition() {
# custom helper functions
array() { param ":append_array $@"; }
parray() { param ":append_array_posix $@"; } # posix version
setup REST error:error on:1 no: export:true plus:true width:35 help:usage abbr:true -- \
"Usage: $PROG [options...] [arguments...]" '' \
'getoptions advanced example' ''
msg label:"OPTION" -- "DESCRIPTION"
flag FLAG_A -a --flag-a on:1 no: init:= export:
flag FLAG_B -b +b --{no-}flag-b on:ON no:NO init:@no
flag FLAG_C -c +c --{no-}flag-c on:1 no:0 init:@unset
flag VERBOSE -v +v --{no-}verbose counter:true init:=0
param PARAM -p --param init:="default"
param LANG --lang init:@none # or init:="$LANG" for using current value
param NUMBER --number validate:number
param RANGE --range validate:'range 10 100' \
-- '10 - 100'
param PATTERN --pattern pattern:'foo | bar' \
-- 'foo | bar'
param BLOOD_TYPE --blood-type validate:blood_type pattern:"$BLOOD_TYPES" \
-- "$BLOOD_TYPES"
param REGEX --regex validate:'regex "^[1-9][0-9]*$"' \
-- '^[1-9][0-9]*$'
param :multiple --multiple init:'MULTIPLE=""' var:MULTIPLE
array ARRAY --array init:'ARRAY=()' var:VALUE
parray PARRAY --array-posix init:'PARRAY=""' var:VALUE
param :'action "$1" p1 p2' --act1 --act2 var:param
option OPTION -o +o --{no-}option on:"on value" no:"no value"
disp :"getoptions parser_definition parse ''" --generate \
-- 'Display parser code'
disp :usage -h --help
disp VERSION --version
}
error() {
case $2 in
unknown) echo "$1" ;;
number:*) echo "Not a number: $3" ;;
range:1) echo "Not a number: $3" ;;
range:2) echo "Out of range ($5 - $6): $3"; return 2 ;;
pattern:"$BLOOD_TYPES") echo "Invalid blood type: $3"; return 2 ;;
regex:*) echo "Not match regex ($4): $3" ;;
*) return 0 ;; # Display default error
esac
return 1
}
number() {
case $OPTARG in (*[!0-9]*) return 1; esac
}
blood_type() {
# Normalization only
case $OPTARG in
a) OPTARG="A" ;;
b) OPTARG="B" ;;
[aA][bB]) OPTARG="AB" ;;
o) OPTARG="O" ;;
esac
}
range() {
number || return 1
[ "$1" -le "$OPTARG" ] && [ "$OPTARG" -le "$2" ] && return 0
return 2
}
regex() {
awk -v s="$OPTARG" -v r="$1" 'BEGIN{exit match(s, r)==0}'
}
multiple() {
MULTIPLE="${MULTIPLE}${MULTIPLE:+,}${OPTARG}"
}
append_array() {
eval "$1+=(\"\$OPTARG\")"
}
append_array_posix() {
# Store multiple (escaped) values in one variable in a POSIX compliant way
set -- "$1" "$OPTARG"
until [ "${2#*\'}" = "$2" ] && eval "$1=\"\$$1 '\${3:-}\$2'\""; do
set -- "$1" "${2#*\'}" "${2%%\'*}'\"'\"'"
done
}
action() {
# Example of passing options and parameters
echo "Do action: option => [$1], param=>[$2, $3], arg => [$OPTARG]"
exit
}
disp_array() {
echo "$1:"
shift
i=0
while [ $# -gt 0 ] && i=$((i + 1)); do
echo " $i: $1"
shift
done
}
eval "$(getoptions parser_definition) exit 1"
echo "FLAG_A: $FLAG_A"
echo "FLAG_B: $FLAG_B"
if [ ${FLAG_C+x} ]; then
echo "FLAG_C: $FLAG_C"
else
echo "FLAG_C: <unset>"
fi
echo "VERBOSE: $VERBOSE"
echo "PARAM: $PARAM"
echo "LANG: $LANG"
echo "NUMBER: $NUMBER"
echo "RANGE: $RANGE"
echo "PATTERN: $PATTERN"
echo "BLOOD_TYPE: $BLOOD_TYPE"
echo "REGEX: $REGEX"
echo "MULTIPLE: $MULTIPLE"
if [ ${#ARRAY[@]} -eq 0 ]; then
disp_array ARRAY
else
disp_array ARRAY "${ARRAY[@]}"
fi
eval disp_array PARRAY "$PARRAY"
echo "OPTION: $OPTION"
echo "VERSION: $VERSION"
disp_array arguments "$@"