1 #!/bin/bash
2 #
3 # Bash implements type -t.
4 #
5 # NOTE: Aliases don't work in batch mode! Interactive only.
6
7 #### getopts empty
8 set --
9 getopts 'a:' opt
10 echo "status=$? opt=$opt OPTARG=$OPTARG"
11 ## stdout: status=1 opt=? OPTARG=
12
13 #### getopts sees unknown arg
14 set -- -Z
15 getopts 'a:' opt
16 echo "status=$? opt=$opt OPTARG=$OPTARG"
17 ## stdout: status=0 opt=? OPTARG=
18
19 #### getopts three invocations
20 set -- -h -c foo
21 getopts 'hc:' opt
22 echo status=$? opt=$opt
23 getopts 'hc:' opt
24 echo status=$? opt=$opt
25 getopts 'hc:' opt
26 echo status=$? opt=$opt
27 ## stdout-json: "status=0 opt=h\nstatus=0 opt=c\nstatus=1 opt=?\n"
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-json: "status=0 opt=c OPTARG=foo\nstatus=0 opt=h OPTARG=\n"
36
37 #### Basic getopts invocation
38 set -- -h -c foo x y z
39 FLAG_h=0
40 FLAG_c=''
41 while getopts "hc:" opt; do
42 case $opt in
43 h) FLAG_h=1 ;;
44 c) FLAG_c="$OPTARG" ;;
45 esac
46 done
47 shift $(( OPTIND - 1 ))
48 echo h=$FLAG_h c=$FLAG_c optind=$OPTIND argv=$@
49 ## stdout: h=1 c=foo optind=4 argv=x y z
50
51 #### getopts with invalid variable name
52 set -- -c foo -h
53 getopts 'hc:' opt-
54 echo status=$? opt=$opt OPTARG=$OPTARG OPTIND=$OPTIND
55 ## stdout: status=2 opt= OPTARG=foo OPTIND=3
56 ## OK bash stdout: status=1 opt= OPTARG=foo OPTIND=3
57 ## OK mksh stdout: status=1 opt= OPTARG= OPTIND=1
58
59 #### getopts with invalid flag
60 set -- -h -x
61 while getopts "hc:" opt; do
62 case $opt in
63 h) FLAG_h=1 ;;
64 c) FLAG_c="$OPTARG" ;;
65 '?') echo ERROR $OPTIND; exit 2; ;;
66 esac
67 done
68 echo status=$?
69 ## stdout: ERROR 3
70 ## status: 2
71
72 #### getopts missing required argument
73 set -- -h -c
74 while getopts "hc:" opt; do
75 case $opt in
76 h) FLAG_h=1 ;;
77 c) FLAG_c="$OPTARG" ;;
78 '?') echo ERROR $OPTIND; exit 2; ;;
79 esac
80 done
81 echo status=$?
82 ## stdout: ERROR 3
83 ## status: 2
84
85 #### getopts doesn't look for flags after args
86 set -- x -h -c y
87 FLAG_h=0
88 FLAG_c=''
89 while getopts "hc:" opt; do
90 case $opt in
91 h) FLAG_h=1 ;;
92 c) FLAG_c="$OPTARG" ;;
93 esac
94 done
95 shift $(( OPTIND - 1 ))
96 echo h=$FLAG_h c=$FLAG_c optind=$OPTIND argv=$@
97 ## stdout: h=0 c= optind=1 argv=x -h -c y
98
99 #### getopts with explicit args
100 # NOTE: Alpine doesn't appear to use this, but bash-completion does.
101 FLAG_h=0
102 FLAG_c=''
103 arg=''
104 set -- A B C
105 while getopts "hc:" opt -h -c foo x y z; do
106 case $opt in
107 h) FLAG_h=1 ;;
108 c) FLAG_c="$OPTARG" ;;
109 esac
110 done
111 echo h=$FLAG_h c=$FLAG_c optind=$OPTIND argv=$@
112 ## STDOUT:
113 h=1 c=foo optind=4 argv=A B C
114 ## END
115
116 #### OPTIND
117 echo $OPTIND
118 ## stdout: 1
119
120 #### OPTIND after multiple getopts with same spec
121 while getopts "hc:" opt; do
122 echo '-'
123 done
124 echo $OPTIND
125
126 set -- -h -c foo x y z
127 while getopts "hc:" opt; do
128 echo '-'
129 done
130 echo $OPTIND
131
132 set --
133 while getopts "hc:" opt; do
134 echo '-'
135 done
136 echo $OPTIND
137 ## stdout-json: "1\n-\n-\n4\n1\n"
138 ## BUG mksh/osh stdout-json: "1\n-\n-\n4\n4\n"
139
140 #### OPTIND after multiple getopts with different spec
141 # Wow this is poorly specified! A fundamental design problem with the global
142 # variable OPTIND.
143 set -- -a
144 while getopts "ab:" opt; do
145 echo '.'
146 done
147 echo $OPTIND
148
149 set -- -c -d -e foo
150 while getopts "cde:" opt; do
151 echo '-'
152 done
153 echo $OPTIND
154
155 set -- -f
156 while getopts "f:" opt; do
157 echo '_'
158 done
159 echo $OPTIND
160 ## stdout-json: ".\n2\n-\n-\n5\n2\n"
161 ## BUG ash/dash stdout-json: ".\n2\n-\n-\n-\n5\n_\n2\n"
162 ## BUG mksh/osh stdout-json: ".\n2\n-\n-\n5\n5\n"
163
164 #### OPTIND narrowed down
165 FLAG_a=
166 FLAG_b=
167 FLAG_c=
168 FLAG_d=
169 FLAG_e=
170 set -- -a
171 while getopts "ab:" opt; do
172 case $opt in
173 a) FLAG_a=1 ;;
174 b) FLAG_b="$OPTARG" ;;
175 esac
176 done
177 # Bash doesn't reset optind! It skips over c! mksh at least warns about this!
178 # You have to reset OPTIND yourself.
179
180 set -- -c -d -e E
181 while getopts "cde:" opt; do
182 case $opt in
183 c) FLAG_c=1 ;;
184 d) FLAG_d=1 ;;
185 e) FLAG_e="$OPTARG" ;;
186 esac
187 done
188
189 echo a=$FLAG_a b=$FLAG_b c=$FLAG_c d=$FLAG_d e=$FLAG_e
190 ## stdout: a=1 b= c=1 d=1 e=E
191 ## BUG bash/mksh/osh stdout: a=1 b= c= d=1 e=E
192
193
194 #### Getopts parses the function's arguments
195 FLAG_h=0
196 FLAG_c=''
197 myfunc() {
198 while getopts "hc:" opt; do
199 case $opt in
200 h) FLAG_h=1 ;;
201 c) FLAG_c="$OPTARG" ;;
202 esac
203 done
204 }
205 set -- -h -c foo x y z
206 myfunc -c bar
207 echo h=$FLAG_h c=$FLAG_c opt=$opt optind=$OPTIND argv=$@
208 ## stdout: h=0 c=bar opt=? optind=3 argv=-h -c foo x y z
209
210 #### Local OPTIND
211 # minimal test case extracted from bash-completion
212 min() {
213 local OPTIND=1
214
215 while getopts "n:e:o:i:s" flag "$@"; do
216 echo "loop $OPTIND";
217 done
218 }
219 min -s
220 ## stdout: loop 2
221
222 #### Flags can be smooshed together, e.g. -ab
223 getopts "ab:c:" opt -ab hi -c hello
224 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
225 getopts "ab:c:" opt -ab hi -c hello
226 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
227 getopts "ab:c:" opt -ab hi -c hello
228 echo OPTIND=$OPTIND opt=$opt OPTARG=$OPTARG
229 ## STDOUT:
230 OPTIND=2 opt=a OPTARG=
231 OPTIND=3 opt=b OPTARG=hi
232 OPTIND=5 opt=c OPTARG=hello
233 ## END
234 ## BUG bash STDOUT:
235 OPTIND=1 opt=a OPTARG=
236 OPTIND=3 opt=b OPTARG=hi
237 OPTIND=5 opt=c OPTARG=hello
238 ## END