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