OILS / spec / builtin-getopts.test.sh View on Github | oils.pub

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