1 | ## oils_failures_allowed: 3
|
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-json: "_tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz\n_tmp/spec-tmp/*.zz\n"
|
155 |
|
156 | #### set -o noglob (bug #698)
|
157 | var='\z'
|
158 | set -f
|
159 | echo $var
|
160 | ## STDOUT:
|
161 | \z
|
162 | ## END
|
163 |
|
164 | #### shopt -s nullglob
|
165 | argv.py _tmp/spec-tmp/*.nonexistent
|
166 | shopt -s nullglob
|
167 | argv.py _tmp/spec-tmp/*.nonexistent
|
168 | ## stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n[]\n"
|
169 | ## N-I dash/mksh/ash stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n['_tmp/spec-tmp/*.nonexistent']\n"
|
170 |
|
171 | #### shopt -s failglob in command context
|
172 | argv.py *.ZZ
|
173 | shopt -s failglob
|
174 | argv.py *.ZZ # nothing is printed, not []
|
175 | echo status=$?
|
176 | ## STDOUT:
|
177 | ['*.ZZ']
|
178 | status=1
|
179 | ## END
|
180 | ## N-I dash/mksh/ash STDOUT:
|
181 | ['*.ZZ']
|
182 | ['*.ZZ']
|
183 | status=0
|
184 | ## END
|
185 |
|
186 | #### shopt -s failglob in loop context
|
187 | for x in *.ZZ; do echo $x; done
|
188 | echo status=$?
|
189 | shopt -s failglob
|
190 | for x in *.ZZ; do echo $x; done
|
191 | echo status=$?
|
192 | ## STDOUT:
|
193 | *.ZZ
|
194 | status=0
|
195 | status=1
|
196 | ## END
|
197 | ## N-I dash/mksh/ash STDOUT:
|
198 | *.ZZ
|
199 | status=0
|
200 | *.ZZ
|
201 | status=0
|
202 | ## END
|
203 |
|
204 | #### shopt -s failglob in array literal context
|
205 | myarr=(*.ZZ)
|
206 | echo "${myarr[@]}"
|
207 | shopt -s failglob
|
208 | myarr=(*.ZZ)
|
209 | echo status=$?
|
210 | ## STDOUT:
|
211 | *.ZZ
|
212 | status=1
|
213 | ## END
|
214 | ## N-I mksh STDOUT:
|
215 | *.ZZ
|
216 | status=0
|
217 | ## END
|
218 | ## N-I dash/ash stdout-json: ""
|
219 | ## N-I dash/ash status: 2
|
220 |
|
221 | #### shopt -s failglob exits properly in command context with set -e
|
222 | set -e
|
223 | argv.py *.ZZ
|
224 | shopt -s failglob
|
225 | argv.py *.ZZ
|
226 | echo status=$?
|
227 | ## STDOUT:
|
228 | ['*.ZZ']
|
229 | ## END
|
230 | ## status: 1
|
231 | ## N-I dash/mksh/ash STDOUT:
|
232 | ['*.ZZ']
|
233 | ## END
|
234 | ## N-I dash/mksh/ash status: 127
|
235 |
|
236 | #### shopt -s failglob exits properly in loop context with set -e
|
237 | set -e
|
238 | for x in *.ZZ; do echo $x; done
|
239 | echo status=$?
|
240 |
|
241 | shopt -s failglob
|
242 | for x in *.ZZ; do echo $x; done
|
243 | echo status=$?
|
244 |
|
245 | ## status: 1
|
246 | ## STDOUT:
|
247 | *.ZZ
|
248 | status=0
|
249 | ## END
|
250 |
|
251 | ## N-I dash/mksh/ash status: 127
|
252 | ## N-I dash/mksh/ash STDOUT:
|
253 | *.ZZ
|
254 | status=0
|
255 | ## END
|
256 |
|
257 | #### shopt -s failglob behavior on single line with semicolon
|
258 | # bash behaves differently when commands are separated by a semicolon than when
|
259 | # separated by a newline. This behavior doesn't make sense or seem to be
|
260 | # intentional, so osh does not mimic it.
|
261 |
|
262 | shopt -s failglob
|
263 | echo *.ZZ; echo status=$? # bash doesn't execute the second part!
|
264 | echo *.ZZ
|
265 | echo status=$? # bash executes this
|
266 |
|
267 | ## STDOUT:
|
268 | status=1
|
269 | ## END
|
270 |
|
271 | ## OK osh STDOUT:
|
272 | status=1
|
273 | status=1
|
274 | ## END
|
275 |
|
276 | ## N-I dash/mksh/ash STDOUT:
|
277 | *.ZZ
|
278 | status=0
|
279 | *.ZZ
|
280 | status=0
|
281 | ## END
|
282 |
|
283 | #### Splitting/Globbing doesn't happen on local assignment
|
284 | cd $REPO_ROOT
|
285 |
|
286 | f() {
|
287 | # Dash splits words and globs before handing it to the 'local' builtin. But
|
288 | # ash doesn't!
|
289 | local foo=$1
|
290 | echo "$foo"
|
291 | }
|
292 | f 'void *'
|
293 | ## stdout: void *
|
294 | ## BUG dash stdout-json: ""
|
295 | ## BUG dash status: 2
|
296 |
|
297 | #### Glob of unescaped [[] and []]
|
298 | touch $TMP/[ $TMP/]
|
299 | cd $TMP
|
300 | echo [\[z] [\]z] # the right way to do it
|
301 | echo [[z] []z] # also accepted
|
302 | ## STDOUT:
|
303 | [ ]
|
304 | [ ]
|
305 | ## END
|
306 |
|
307 | #### Glob of negated unescaped [[] and []]
|
308 | # osh does this "correctly" because it defers to libc!
|
309 | touch $TMP/_G
|
310 | cd $TMP
|
311 | echo _[^\[z] _[^\]z] # the right way to do it
|
312 | echo _[^[z] _[^]z] # also accepted
|
313 | ## STDOUT:
|
314 | _G _G
|
315 | _G _G
|
316 | ## END
|
317 | ## BUG dash/mksh STDOUT:
|
318 | _[^[z] _[^]z]
|
319 | _[^[z] _[^]z]
|
320 | ## END
|
321 |
|
322 | #### PatSub of unescaped [[] and []]
|
323 | x='[foo]'
|
324 | echo ${x//[\[z]/<} # the right way to do it
|
325 | echo ${x//[\]z]/>}
|
326 | echo ${x//[[z]/<} # also accepted
|
327 | echo ${x//[]z]/>}
|
328 | ## STDOUT:
|
329 | <foo]
|
330 | [foo>
|
331 | <foo]
|
332 | [foo>
|
333 | ## END
|
334 | ## N-I dash stdout-json: ""
|
335 | ## N-I dash status: 2
|
336 |
|
337 | #### PatSub of negated unescaped [[] and []]
|
338 | x='[foo]'
|
339 | echo ${x//[^\[z]/<} # the right way to do it
|
340 | echo ${x//[^\]z]/>}
|
341 | echo ${x//[^[z]/<} # also accepted
|
342 | #echo ${x//[^]z]/>} # only busybox ash interprets as ^\]
|
343 | ## STDOUT:
|
344 | [<<<<
|
345 | >>>>]
|
346 | [<<<<
|
347 | ## END
|
348 | # mksh is doing something very odd, ignoring ^ altogether?
|
349 | ## BUG mksh STDOUT:
|
350 | <foo]
|
351 | [foo>
|
352 | <foo]
|
353 | ## END
|
354 | ## N-I dash stdout-json: ""
|
355 | ## N-I dash status: 2
|
356 |
|
357 | #### Glob unicode char
|
358 |
|
359 | touch $TMP/__a__
|
360 | touch $TMP/__μ__
|
361 | cd $TMP
|
362 |
|
363 | echo __?__
|
364 |
|
365 | ## STDOUT:
|
366 | __a__ __μ__
|
367 | ## END
|
368 | ## BUG dash/mksh/ash STDOUT:
|
369 | __a__
|
370 | ## END
|
371 | # note: zsh also passes this, but it doesn't run with this file.
|
372 |
|
373 | #### dotglob (bash option that dashglob is roughly consistent with)
|
374 | mkdir -p $TMP/dotglob
|
375 | cd $TMP/dotglob
|
376 | touch .foorc other
|
377 |
|
378 | echo *
|
379 | shopt -s dotglob
|
380 | echo *
|
381 | ## STDOUT:
|
382 | other
|
383 | .foorc other
|
384 | ## END
|
385 | ## N-I dash/mksh/ash STDOUT:
|
386 | other
|
387 | other
|
388 | ## END
|