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