1 # builtin-getopts.test.sh
2
3 #### getopts empty
4 set --
5 getopts 'a:' opt
6 echo "status=$? opt=$opt OPTARG=$OPTARG"
7 ## stdout: status=1 opt=? OPTARG=
8
9 #### getopts sees unknown arg
10 set -- -Z
11 getopts 'a:' opt
12 echo "status=$? opt=$opt OPTARG=$OPTARG"
13 ## stdout: status=0 opt=? OPTARG=
14
15 #### getopts three invocations
16 set -- -h -c foo
17 getopts 'hc:' opt
18 echo status=$? opt=$opt
19 getopts 'hc:' opt
20 echo status=$? opt=$opt
21 getopts 'hc:' opt
22 echo status=$? opt=$opt
23 ## STDOUT:
24 status=0 opt=h
25 status=0 opt=c
26 status=1 opt=?
27 ## END
28
29 #### getopts resets OPTARG
30 set -- -c foo -h
31 getopts 'hc:' opt
32 echo status=$? opt=$opt OPTARG=$OPTARG
33 getopts 'hc:' opt
34 echo status=$? opt=$opt OPTARG=$OPTARG
35 ## STDOUT:
36 status=0 opt=c OPTARG=foo
37 status=0 opt=h OPTARG=
38 ## END
39
40 #### Basic getopts invocation
41 set -- -h -c foo x y z
42 FLAG_h=0
43 FLAG_c=''
44 while getopts "hc:" opt; do
45 case $opt in
46 h) FLAG_h=1 ;;
47 c) FLAG_c="$OPTARG" ;;
48 esac
49 done
50 shift $(( OPTIND - 1 ))
51 echo h=$FLAG_h c=$FLAG_c optind=$OPTIND argv=$@
52 ## stdout: h=1 c=foo optind=4 argv=x y z
53
54 #### getopts with invalid variable name
55 set -- -c foo -h
56 getopts 'hc:' opt-
57 echo status=$? opt=$opt OPTARG=$OPTARG OPTIND=$OPTIND
58 ## stdout: status=2 opt= OPTARG=foo OPTIND=3
59 ## OK bash stdout: status=1 opt= OPTARG=foo OPTIND=3
60 ## OK mksh stdout: status=1 opt= OPTARG= OPTIND=1
61
62 #### getopts with invalid flag
63 set -- -h -x
64 while getopts "hc:" opt; do
65 case $opt in
66 h) FLAG_h=1 ;;
67 c) FLAG_c="$OPTARG" ;;
68 '?') echo ERROR $OPTIND; exit 2; ;;
69 esac
70 done
71 echo status=$?
72 ## stdout: ERROR 3
73 ## status: 2
74
75 #### getopts with with -
76 set -- -h -
77 echo "$@"
78 while getopts "hc:" opt; do
79 case $opt in
80 h) FLAG_h=1 ;;
81 c) FLAG_c="$OPTARG" ;;
82 '?') echo ERROR $OPTIND; exit 2; ;;
83 esac
84 done
85 echo status=$?
86 ## STDOUT:
87 -h -
88 status=0
89 ## END
90
91 #### getopts missing required argument
92 set -- -h -c
93 while getopts "hc:" opt; do
94 case $opt in
95 h) FLAG_h=1 ;;
96 c) FLAG_c="$OPTARG" ;;
97 '?') echo ERROR $OPTIND; exit 2; ;;
98 esac
99 done
100 echo status=$?
101 ## stdout: ERROR 3
102 ## status: 2
103
104 #### getopts doesn't look for flags after args
105 set -- x -h -c y
106 FLAG_h=0
107 FLAG_c=''
108 while getopts "hc:" opt; do
109 case $opt in
110 h) FLAG_h=1 ;;
111 c) FLAG_c="$OPTARG" ;;
112 esac
113 done
114 shift $(( OPTIND - 1 ))
115 echo h=$FLAG_h c=$FLAG_c optind=$OPTIND argv=$@
116 ## stdout: h=0 c= optind=1 argv=x -h -c y
117
118 #### getopts with explicit args
119 # NOTE: Alpine doesn't appear to use this, but bash-completion does.
120 FLAG_h=0
121 FLAG_c=''
122 arg=''
123 set -- A B C
124 while getopts "hc:" opt -h -c foo x y z; do
125 case $opt in
126 h) FLAG_h=1 ;;
127 c) FLAG_c="$OPTARG" ;;
128 esac
129 done
130 echo h=$FLAG_h c=$FLAG_c optind=$OPTIND argv=$@
131 ## STDOUT:
132 h=1 c=foo optind=4 argv=A B C
133 ## END
134
135 #### OPTIND
136 echo $OPTIND
137 ## stdout: 1
138
139 #### OPTIND after multiple getopts with same spec
140 while getopts "hc:" opt; do
141 echo '-'
142 done
143 echo $OPTIND
144
145 set -- -h -c foo x y z
146 while getopts "hc:" opt; do
147 echo '-'
148 done
149 echo $OPTIND
150
151 set --
152 while getopts "hc:" opt; do
153 echo '-'
154 done
155 echo $OPTIND
156 ## stdout-json: "1\n-\n-\n4\n1\n"
157 ## BUG mksh/osh stdout-json: "1\n-\n-\n4\n4\n"
158
159 #### OPTIND after multiple getopts with different spec
160 # Wow this is poorly specified! A fundamental design problem with the global
161 # variable OPTIND.
162 set -- -a
163 while getopts "ab:" opt; do
164 echo '.'
165 done
166 echo $OPTIND
167
168 set -- -c -d -e foo
169 while getopts "cde:" opt; do
170 echo '-'
171 done
172 echo $OPTIND
173
174 set -- -f
175 while getopts "f:" opt; do
176 echo '_'
177 done
178 echo $OPTIND
179 ## stdout-json: ".\n2\n-\n-\n5\n2\n"
180 ## BUG ash/dash stdout-json: ".\n2\n-\n-\n-\n5\n_\n2\n"
181 ## BUG mksh/osh stdout-json: ".\n2\n-\n-\n5\n5\n"
182
183 #### OPTIND narrowed down
184 FLAG_a=
185 FLAG_b=
186 FLAG_c=
187 FLAG_d=
188 FLAG_e=
189 set -- -a
190 while getopts "ab:" opt; do
191 case $opt in
192 a) FLAG_a=1 ;;
193 b) FLAG_b="$OPTARG" ;;
194 esac
195 done
196 # Bash doesn't reset optind! It skips over c! mksh at least warns about this!
197 # You have to reset OPTIND yourself.
198
199 set -- -c -d -e E
200 while getopts "cde:" opt; do
201 case $opt in
202 c) FLAG_c=1 ;;
203 d) FLAG_d=1 ;;
204 e) FLAG_e="$OPTARG" ;;
205 esac
206 done
207
208 echo a=$FLAG_a b=$FLAG_b c=$FLAG_c d=$FLAG_d e=$FLAG_e
209 ## stdout: a=1 b= c=1 d=1 e=E
210 ## BUG bash/mksh/osh stdout: a=1 b= c= d=1 e=E
211
212
213 #### Getopts parses the function's arguments
214 FLAG_h=0
215 FLAG_c=''
216 myfunc() {
217 while getopts "hc:" opt; do
218 case $opt in
219 h) FLAG_h=1 ;;
220 c) FLAG_c="$OPTARG" ;;
221 esac
222 done
223 }
224 set -- -h -c foo x y z
225 myfunc -c bar
226 echo h=$FLAG_h c=$FLAG_c opt=$opt optind=$OPTIND argv=$@
227 ## stdout: h=0 c=bar opt=? optind=3 argv=-h -c foo x y z
228
229 #### Local OPTIND
230 # minimal test case extracted from bash-completion
231 min() {
232 local OPTIND=1
233
234 while getopts "n:e:o:i:s" flag "$@"; do
235 echo "loop $OPTIND";
236 done
237 }
238 min -s
239 ## stdout: loop 2
240
241 #### two flags: -ab
242 getopts "ab" opt -ab
243 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
244 getopts "ab" opt -ab
245 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
246 ## STDOUT:
247 OPTIND=1 opt=a OPTARG=
248 OPTIND=2 opt=b OPTARG=
249 ## END
250 ## OK dash/mksh/ash STDOUT:
251 OPTIND=2 opt=a OPTARG=
252 OPTIND=2 opt=b OPTARG=
253 ## END
254
255 #### flag and arg: -c10
256 getopts "c:" opt -c10
257 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
258 getopts "c:" opt -c10
259 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
260 ## STDOUT:
261 OPTIND=2 opt=c OPTARG=10
262 OPTIND=2 opt=? OPTARG=
263 ## END
264 ## BUG dash STDOUT:
265 OPTIND=2 opt=c OPTARG=10
266 OPTIND=2 opt=? OPTARG=10
267 ## END
268
269 #### More Smooshing 1
270 getopts "ab:c:" opt -ab hi -c hello
271 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
272 getopts "ab:c:" opt -ab hi -c hello
273 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
274 getopts "ab:c:" opt -ab hi -c hello
275 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
276 ## STDOUT:
277 OPTIND=1 opt=a OPTARG=
278 OPTIND=3 opt=b OPTARG=hi
279 OPTIND=5 opt=c OPTARG=hello
280 ## END
281 ## OK dash/mksh/ash STDOUT:
282 OPTIND=2 opt=a OPTARG=
283 OPTIND=3 opt=b OPTARG=hi
284 OPTIND=5 opt=c OPTARG=hello
285 ## END
286
287 #### More Smooshing 2
288 getopts "abc:" opt -abc10
289 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
290 getopts "abc:" opt -abc10
291 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
292 getopts "abc:" opt -abc10
293 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
294 ## STDOUT:
295 OPTIND=1 opt=a OPTARG=
296 OPTIND=1 opt=b OPTARG=
297 OPTIND=2 opt=c OPTARG=10
298 ## END
299 ## OK dash/mksh/ash STDOUT:
300 OPTIND=2 opt=a OPTARG=
301 OPTIND=2 opt=b OPTARG=
302 OPTIND=2 opt=c OPTARG=10
303 ## END
304
305 #### OPTIND should be >= 1 (regression)
306 OPTIND=-1
307 getopts a: foo
308 echo status=$?
309
310 OPTIND=0
311 getopts a: foo
312 echo status=$?
313 ## STDOUT:
314 status=1
315 status=1
316 ## END
317 ## OK dash status: 2
318 ## OK dash stdout-json: ""