1 ## compare_shells: bash mksh
2 ## oils_failures_allowed: 3
3
4 # TODO: can also run against ksh, brush, sush
5
6 # Test extended glob matching with [[, case, etc.
7
8 #### @ matches exactly one
9 [[ --verbose == --@(help|verbose) ]] && echo TRUE
10 [[ --oops == --@(help|verbose) ]] || echo FALSE
11 ## STDOUT:
12 TRUE
13 FALSE
14 ## END
15
16 #### @() with variable arms
17 choice1='help'
18 choice2='verbose'
19 [[ --verbose == --@($choice1|$choice2) ]] && echo TRUE
20 [[ --oops == --@($choice1|$choice2) ]] || echo FALSE
21 ## STDOUT:
22 TRUE
23 FALSE
24 ## END
25
26 #### extglob in variable
27 shopt -s extglob
28
29 # this syntax requires extglob in bash!!
30 # OSH never allows it
31 g=--@(help|verbose)
32
33 quoted='--@(help|verbose)'
34
35 [[ --help == $g ]] && echo TRUE
36 [[ --verbose == $g ]] && echo TRUE
37 [[ -- == $g ]] || echo FALSE
38 [[ --help == $q ]] || echo FALSE
39 [[ -- == $q ]] || echo FALSE
40 ## STDOUT:
41 TRUE
42 TRUE
43 FALSE
44 FALSE
45 FALSE
46 ## END
47 ## N-I mksh STDOUT:
48 FALSE
49 FALSE
50 FALSE
51 ## END
52
53 #### Matching literal '@(cc)'
54
55 # extglob is OFF. Doesn't affect bash or mksh!
56 [[ cc == @(cc) ]]
57 echo status=$?
58 [[ cc == '@(cc)' ]]
59 echo status=$?
60
61 shopt -s extglob
62
63 [[ cc == @(cc) ]]
64 echo status=$?
65 [[ cc == '@(cc)' ]]
66 echo status=$?
67
68 ## STDOUT:
69 status=0
70 status=1
71 status=0
72 status=1
73 ## END
74
75 #### nested @()
76 shopt -s extglob
77 pat='--@(help|verbose|no-@(long|short)-option)'
78 [[ --no-long-option == $pat ]] && echo TRUE
79 [[ --no-short-option == $pat ]] && echo TRUE
80 [[ --help == $pat ]] && echo TRUE
81 [[ --oops == $pat ]] || echo FALSE
82 ## STDOUT:
83 TRUE
84 TRUE
85 TRUE
86 FALSE
87 ## END
88 ## BUG mksh STDOUT:
89 FALSE
90 ## END
91
92 #### nested @() with quotes and vars
93 shopt -s extglob
94 prefix=no
95 [[ --no-long-option == --@(help|verbose|$prefix-@(long|short)-'option') ]] &&
96 echo TRUE
97 ## STDOUT:
98 TRUE
99 ## END
100
101 #### ? matches 0 or 1
102 [[ -- == --?(help|verbose) ]] && echo TRUE
103 [[ --oops == --?(help|verbose) ]] || echo FALSE
104 ## STDOUT:
105 TRUE
106 FALSE
107 ## END
108
109 #### + matches 1 or more
110 [[ --helphelp == --+(help|verbose) ]] && echo TRUE
111 [[ -- == --+(help|verbose) ]] || echo FALSE
112 ## STDOUT:
113 TRUE
114 FALSE
115 ## END
116
117 #### * matches 0 or more
118 [[ -- == --*(help|verbose) ]] && echo TRUE
119 [[ --oops == --*(help|verbose) ]] || echo FALSE
120 ## STDOUT:
121 TRUE
122 FALSE
123 ## END
124
125 #### simple repetition with *(foo) and +(Foo)
126 [[ foofoo == *(foo) ]] && echo TRUE
127 [[ foofoo == +(foo) ]] && echo TRUE
128 ## STDOUT:
129 TRUE
130 TRUE
131 ## END
132
133 #### ! matches none
134 [[ --oops == --!(help|verbose) ]] && echo TRUE
135 [[ --help == --!(help|verbose) ]] || echo FALSE
136 ## STDOUT:
137 TRUE
138 FALSE
139 ## END
140
141 #### match is anchored
142 [[ foo_ == @(foo) ]] || echo FALSE
143 [[ _foo == @(foo) ]] || echo FALSE
144 [[ foo == @(foo) ]] && echo TRUE
145 ## STDOUT:
146 FALSE
147 FALSE
148 TRUE
149 ## END
150
151 #### repeated match is anchored
152 [[ foofoo_ == +(foo) ]] || echo FALSE
153 [[ _foofoo == +(foo) ]] || echo FALSE
154 [[ foofoo == +(foo) ]] && echo TRUE
155 ## STDOUT:
156 FALSE
157 FALSE
158 TRUE
159 ## END
160
161 #### repetition with glob
162 # NOTE that * means two different things here
163 [[ foofoo_foo__foo___ == *(foo*) ]] && echo TRUE
164 [[ Xoofoo_foo__foo___ == *(foo*) ]] || echo FALSE
165 ## STDOUT:
166 TRUE
167 FALSE
168 ## END
169
170 #### No brace expansion in ==
171 [[ --X{a,b}X == --@(help|X{a,b}X) ]] && echo TRUE
172 [[ --oops == --@(help|X{a,b}X) ]] || echo FALSE
173 ## STDOUT:
174 TRUE
175 FALSE
176 ## END
177
178 #### adjacent extglob
179 [[ --help == @(--|++)@(help|verbose) ]] && echo TRUE
180 [[ ++verbose == @(--|++)@(help|verbose) ]] && echo TRUE
181 ## STDOUT:
182 TRUE
183 TRUE
184 ## END
185
186 #### nested extglob
187 [[ --help == --@(help|verbose=@(1|2)) ]] && echo TRUE
188 [[ --verbose=1 == --@(help|verbose=@(1|2)) ]] && echo TRUE
189 [[ --verbose=2 == --@(help|verbose=@(1|2)) ]] && echo TRUE
190 [[ --verbose == --@(help|verbose=@(1|2)) ]] || echo FALSE
191 ## STDOUT:
192 TRUE
193 TRUE
194 TRUE
195 FALSE
196 ## END
197
198 #### extglob empty string
199 shopt -s extglob
200 [[ '' == @(foo|bar) ]] || echo FALSE
201 [[ '' == @(foo||bar) ]] && echo TRUE
202 ## STDOUT:
203 FALSE
204 TRUE
205 ## END
206
207 #### extglob empty pattern
208 shopt -s extglob
209 [[ '' == @() ]] && echo TRUE
210 [[ '' == @(||) ]] && echo TRUE
211 [[ X == @() ]] || echo FALSE
212 [[ '|' == @(||) ]] || echo FALSE
213 ## STDOUT:
214 TRUE
215 TRUE
216 FALSE
217 FALSE
218 ## END
219
220 #### case with extglob
221 shopt -s extglob
222 for word in --help --verbose --unmatched -- -zxzx -; do
223 case $word in
224 --@(help|verbose) )
225 echo A
226 continue
227 ;;
228 ( --?(b|c) )
229 echo B
230 continue
231 ;;
232 ( -+(x|z) )
233 echo C
234 continue
235 ;;
236 ( -*(x|z) )
237 echo D
238 continue
239 ;;
240 *)
241 echo U
242 continue
243 ;;
244 esac
245 done
246 ## STDOUT:
247 A
248 A
249 U
250 B
251 C
252 D
253 ## END
254
255 #### [[ $x == !($str) ]]
256 shopt -s extglob
257 empty=''
258 str='x'
259 [[ $empty == !($str) ]] && echo TRUE # test glob match
260 [[ $str == !($str) ]] || echo FALSE
261 ## STDOUT:
262 TRUE
263 FALSE
264 ## END
265
266 #### Turning extglob on changes the meaning of [[ !(str) ]] in bash
267 empty=''
268 str='x'
269 [[ !($empty) ]] && echo TRUE # test if $empty is empty
270 [[ !($str) ]] || echo FALSE # test if $str is empty
271 shopt -s extglob # mksh doesn't have this
272 [[ !($empty) ]] && echo TRUE # negated glob
273 [[ !($str) ]] && echo TRUE # negated glob
274 ## STDOUT:
275 TRUE
276 FALSE
277 TRUE
278 TRUE
279 ## END
280 ## N-I mksh/ksh STDOUT:
281 TRUE
282 TRUE
283 TRUE
284 ## END
285
286 #### With extglob on, !($str) on the left or right of == has different meanings
287 shopt -s extglob
288 str='x'
289 [[ 1 == !($str) ]] && echo TRUE # glob match
290
291 ## STDOUT:
292 TRUE
293 ## END
294
295 #### extglob inside arg word
296 shopt -s extglob
297 [[ foo == @(foo|bar) ]] && echo rhs
298 [[ foo == ${unset:-@(foo|bar)} ]] && echo 'rhs arg'
299 [[ fo == ${unset:-@(foo|bar)} ]] || echo nope
300 ## STDOUT:
301 rhs
302 rhs arg
303 nope
304 ## END
305 ## BUG mksh/ksh STDOUT:
306 rhs
307 nope
308 ## END
309
310 #### extglob is not detected in regex!
311 shopt -s extglob
312 [[ foo =~ ^@(foo|bar)$ ]] || echo FALSE
313 ## STDOUT:
314 FALSE
315 ## END
316 ## N-I mksh/ksh stdout-json: ""
317 ## N-I mksh/ksh status: 1
318
319 #### regular glob of single unicode char
320 shopt -s extglob
321 [[ __a__ == __?__ ]]
322 echo $?
323 [[ __μ__ == __?__ ]]
324 echo $?
325 ## STDOUT:
326 0
327 0
328 ## END
329 ## BUG mksh STDOUT:
330 0
331 1
332 ## END
333
334 #### extended glob of single unicode char
335 shopt -s extglob
336 [[ __a__ == @(__?__) ]]
337 echo $?
338 [[ __μ__ == @(__?__) ]]
339 echo $?
340 ## STDOUT:
341 0
342 0
343 ## END
344 ## BUG mksh STDOUT:
345 0
346 1
347 ## END
348
349 #### Extended glob in ${x//pat/replace}
350 # not supported in OSH due to GlobToERE() strategy for positional info
351
352 shopt -s extglob
353 x=foo.py
354 echo ${x//@(?.py)/Z}
355 ## STDOUT:
356 foZ
357 ## END
358 ## N-I osh status: 1
359 ## N-I osh stdout-json: ""
360
361 #### Extended glob in ${x%PATTERN}
362
363 shopt -s extglob
364 x=foo.py
365 echo 'strip % ' ${x%.@(py|cc)}
366 echo 'strip %%' ${x%%.@(py|cc)}
367 echo 'strip # ' ${x#@(foo)}
368 echo 'strip ##' ${x##@(foo)}
369
370 ## STDOUT:
371 strip % foo
372 strip %% foo
373 strip # .py
374 strip ## .py
375 ## END