1 ## oils_failures_allowed: 2
2 ## compare_shells: bash dash mksh ash
3
4 #### glob double quote escape
5 echo "*.sh"
6 ## stdout: *.sh
7
8 #### glob single quote escape
9 echo "*.sh"
10 ## stdout: *.sh
11
12 #### glob backslash escape
13 echo \*.sh
14 ## stdout: *.sh
15
16 #### 1 char glob
17 cd $REPO_ROOT
18 echo [b]in
19 ## stdout: bin
20
21 #### 0 char glob -- does NOT work
22 echo []bin
23 ## stdout: []bin
24
25 #### looks like glob at the start, but isn't
26 echo [bin
27 ## stdout: [bin
28
29 #### looks like glob plus negation at the start, but isn't
30 echo [!bin
31 ## stdout: [!bin
32
33 #### glob can expand to command and arg
34 cd $REPO_ROOT
35 spec/testdata/echo.s[hz]
36 ## stdout: spec/testdata/echo.sz
37
38 #### glob after var expansion
39 touch _tmp/a.A _tmp/aa.A _tmp/b.B
40 f="_tmp/*.A"
41 g="$f _tmp/*.B"
42 echo $g
43 ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B
44
45 #### quoted var expansion with glob meta characters
46 touch _tmp/a.A _tmp/aa.A _tmp/b.B
47 f="_tmp/*.A"
48 echo "[ $f ]"
49 ## stdout: [ _tmp/*.A ]
50
51 #### glob after "$@" expansion
52 fun() {
53 echo "$@"
54 }
55 fun '_tmp/*.B'
56 ## stdout: _tmp/*.B
57
58 #### glob after $@ expansion
59 touch _tmp/b.B
60 fun() {
61 echo $@
62 }
63 fun '_tmp/*.B'
64 ## stdout: _tmp/b.B
65
66 #### no glob after ~ expansion
67 HOME=*
68 echo ~/*.py
69 ## stdout: */*.py
70
71 #### store literal globs in array then expand
72 touch _tmp/a.A _tmp/aa.A _tmp/b.B
73 g=("_tmp/*.A" "_tmp/*.B")
74 echo ${g[@]}
75 ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B
76 ## N-I dash/ash stdout-json: ""
77 ## N-I dash/ash status: 2
78
79 #### glob inside array
80 touch _tmp/a.A _tmp/aa.A _tmp/b.B
81 g=(_tmp/*.A _tmp/*.B)
82 echo "${g[@]}"
83 ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B
84 ## N-I dash/ash stdout-json: ""
85 ## N-I dash/ash status: 2
86
87 #### glob with escaped - in char class
88 touch _tmp/foo.-
89 touch _tmp/c.C
90 echo _tmp/*.[C-D] _tmp/*.[C\-D]
91 ## stdout: _tmp/c.C _tmp/c.C _tmp/foo.-
92
93 #### glob with char class expression
94 # note: mksh doesn't support [[:punct:]] ?
95 touch _tmp/e.E _tmp/foo.-
96 echo _tmp/*.[[:punct:]E]
97 ## stdout: _tmp/e.E _tmp/foo.-
98 ## BUG mksh stdout: _tmp/*.[[:punct:]E]
99
100 #### glob double quotes
101 # note: mksh doesn't support [[:punct:]] ?
102 touch _tmp/\"quoted.py\"
103 echo _tmp/\"*.py\"
104 ## stdout: _tmp/"quoted.py"
105
106 #### glob escaped
107 # - mksh doesn't support [[:punct:]] ?
108 # - python shell fails because \[ not supported!
109 touch _tmp/\[abc\] _tmp/\?
110 echo _tmp/\[???\] _tmp/\?
111 ## stdout: _tmp/[abc] _tmp/?
112
113 #### : escaped
114
115 touch _tmp/foo.-
116 echo _tmp/*.[[:punct:]] _tmp/*.[[:punct\:]]
117
118 ## STDOUT:
119 _tmp/foo.- _tmp/*.[[:punct:]]
120 ## END
121
122 ## BUG mksh STDOUT:
123 _tmp/*.[[:punct:]] _tmp/*.[[:punct:]]
124 ## END
125
126 ## BUG bash/ash STDOUT:
127 _tmp/foo.- _tmp/foo.-
128 ## END
129
130 #### Glob after var manipulation
131 touch _tmp/foo.zzz _tmp/bar.zzz
132 g='_tmp/*.zzzZ'
133 echo $g ${g%Z}
134 ## stdout: _tmp/*.zzzZ _tmp/bar.zzz _tmp/foo.zzz
135
136 #### Glob after part joining
137 touch _tmp/foo.yyy _tmp/bar.yyy
138 g='_tmp/*.yy'
139 echo $g ${g}y
140 ## stdout: _tmp/*.yy _tmp/bar.yyy _tmp/foo.yyy
141
142 #### Glob flags on file system
143 touch _tmp/-n _tmp/zzzzz
144 cd _tmp
145 echo -* hello zzzz?
146 ## stdout-json: "hello zzzzz"
147
148 #### set -o noglob
149 cd $REPO_ROOT
150 touch _tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz
151 echo _tmp/spec-tmp/*.zz
152 set -o noglob
153 echo _tmp/spec-tmp/*.zz
154 ## STDOUT:
155 _tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz
156 _tmp/spec-tmp/*.zz
157 ## END
158
159 #### set -o noglob (bug #698)
160 var='\z'
161 set -f
162 echo $var
163 ## STDOUT:
164 \z
165 ## END
166
167 #### shopt -s nullglob
168 argv.py _tmp/spec-tmp/*.nonexistent
169 shopt -s nullglob
170 argv.py _tmp/spec-tmp/*.nonexistent
171 ## STDOUT:
172 ['_tmp/spec-tmp/*.nonexistent']
173 []
174 ## END
175 ## N-I dash/mksh/ash STDOUT:
176 ['_tmp/spec-tmp/*.nonexistent']
177 ['_tmp/spec-tmp/*.nonexistent']
178 ## END
179
180 #### shopt -s failglob in command context
181 argv.py *.ZZ
182 shopt -s failglob
183 argv.py *.ZZ # nothing is printed, not []
184 echo status=$?
185 ## STDOUT:
186 ['*.ZZ']
187 status=1
188 ## END
189 ## N-I dash/mksh/ash STDOUT:
190 ['*.ZZ']
191 ['*.ZZ']
192 status=0
193 ## END
194
195 #### shopt -s failglob in loop context
196 for x in *.ZZ; do echo $x; done
197 echo status=$?
198 shopt -s failglob
199 for x in *.ZZ; do echo $x; done
200 echo status=$?
201 ## STDOUT:
202 *.ZZ
203 status=0
204 status=1
205 ## END
206 ## N-I dash/mksh/ash STDOUT:
207 *.ZZ
208 status=0
209 *.ZZ
210 status=0
211 ## END
212
213 #### shopt -s failglob in array literal context
214 myarr=(*.ZZ)
215 echo "${myarr[@]}"
216 shopt -s failglob
217 myarr=(*.ZZ)
218 echo status=$?
219 ## STDOUT:
220 *.ZZ
221 status=1
222 ## END
223 ## N-I mksh STDOUT:
224 *.ZZ
225 status=0
226 ## END
227 ## N-I dash/ash stdout-json: ""
228 ## N-I dash/ash status: 2
229
230 #### shopt -s failglob exits properly in command context with set -e
231 set -e
232 argv.py *.ZZ
233 shopt -s failglob
234 argv.py *.ZZ
235 echo status=$?
236 ## STDOUT:
237 ['*.ZZ']
238 ## END
239 ## status: 1
240 ## N-I dash/mksh/ash STDOUT:
241 ['*.ZZ']
242 ## END
243 ## N-I dash/mksh/ash status: 127
244
245 #### shopt -s failglob exits properly in loop context with set -e
246 set -e
247 for x in *.ZZ; do echo $x; done
248 echo status=$?
249
250 shopt -s failglob
251 for x in *.ZZ; do echo $x; done
252 echo status=$?
253
254 ## status: 1
255 ## STDOUT:
256 *.ZZ
257 status=0
258 ## END
259
260 ## N-I dash/mksh/ash status: 127
261 ## N-I dash/mksh/ash STDOUT:
262 *.ZZ
263 status=0
264 ## END
265
266 #### shopt -s failglob behavior on single line with semicolon
267 # bash behaves differently when commands are separated by a semicolon than when
268 # separated by a newline. This behavior doesn't make sense or seem to be
269 # intentional, so osh does not mimic it.
270
271 shopt -s failglob
272 echo *.ZZ; echo status=$? # bash doesn't execute the second part!
273 echo *.ZZ
274 echo status=$? # bash executes this
275
276 ## STDOUT:
277 status=1
278 ## END
279
280 ## OK osh STDOUT:
281 status=1
282 status=1
283 ## END
284
285 ## N-I dash/mksh/ash STDOUT:
286 *.ZZ
287 status=0
288 *.ZZ
289 status=0
290 ## END
291
292 #### Splitting/Globbing doesn't happen on local assignment
293 cd $REPO_ROOT
294
295 f() {
296 # Dash splits words and globs before handing it to the 'local' builtin. But
297 # ash doesn't!
298 local foo=$1
299 echo "$foo"
300 }
301 f 'void *'
302 ## stdout: void *
303 ## BUG dash stdout-json: ""
304 ## BUG dash status: 2
305
306 #### Glob of unescaped [[] and []]
307 touch $TMP/[ $TMP/]
308 cd $TMP
309 echo [\[z] [\]z] # the right way to do it
310 echo [[z] []z] # also accepted
311 ## STDOUT:
312 [ ]
313 [ ]
314 ## END
315
316 #### Glob of negated unescaped [[] and []]
317 # osh does this "correctly" because it defers to libc!
318 touch $TMP/_G
319 cd $TMP
320 echo _[^\[z] _[^\]z] # the right way to do it
321 echo _[^[z] _[^]z] # also accepted
322 ## STDOUT:
323 _G _G
324 _G _G
325 ## END
326 ## BUG dash/mksh STDOUT:
327 _[^[z] _[^]z]
328 _[^[z] _[^]z]
329 ## END
330
331 #### PatSub of unescaped [[] and []]
332 x='[foo]'
333 echo ${x//[\[z]/<} # the right way to do it
334 echo ${x//[\]z]/>}
335 echo ${x//[[z]/<} # also accepted
336 echo ${x//[]z]/>}
337 ## STDOUT:
338 <foo]
339 [foo>
340 <foo]
341 [foo>
342 ## END
343 ## N-I dash stdout-json: ""
344 ## N-I dash status: 2
345
346 #### PatSub of negated unescaped [[] and []]
347 x='[foo]'
348 echo ${x//[^\[z]/<} # the right way to do it
349 echo ${x//[^\]z]/>}
350 echo ${x//[^[z]/<} # also accepted
351 #echo ${x//[^]z]/>} # only busybox ash interprets as ^\]
352 ## STDOUT:
353 [<<<<
354 >>>>]
355 [<<<<
356 ## END
357 # mksh is doing something very odd, ignoring ^ altogether?
358 ## BUG mksh STDOUT:
359 <foo]
360 [foo>
361 <foo]
362 ## END
363 ## N-I dash stdout-json: ""
364 ## N-I dash status: 2
365
366 #### Glob unicode char
367
368 touch $TMP/__a__
369 touch $TMP/__μ__
370 cd $TMP
371
372 echo __?__
373
374 ## STDOUT:
375 __a__ __μ__
376 ## END
377 ## BUG dash/mksh/ash STDOUT:
378 __a__
379 ## END
380 # note: zsh also passes this, but it doesn't run with this file.
381
382 #### dotglob (bash option that dashglob is roughly consistent with)
383 mkdir -p $TMP/dotglob
384 cd $TMP/dotglob
385 touch .foorc other
386
387 echo *
388 shopt -s dotglob
389 echo * | sort
390 ## STDOUT:
391 other
392 .foorc other
393 ## END
394 ## N-I dash/mksh/ash STDOUT:
395 other
396 other
397 ## END