1 #!/usr/bin/env bash
2 #
3 # NOTE: Could move spec/03-glob.sh here.
4
5 #### glob double quote escape
6 echo "*.sh"
7 ## stdout: *.sh
8
9 #### glob single quote escape
10 echo "*.sh"
11 ## stdout: *.sh
12
13 #### glob backslash escape
14 echo \*.sh
15 ## stdout: *.sh
16
17 #### 1 char glob
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 spec/testdata/echo.s[hz]
35 ## stdout: spec/testdata/echo.sz
36
37 #### glob after var expansion
38 touch _tmp/a.A _tmp/aa.A _tmp/b.B
39 f="_tmp/*.A"
40 g="$f _tmp/*.B"
41 echo $g
42 ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B
43
44 #### quoted var expansion with glob meta characters
45 touch _tmp/a.A _tmp/aa.A _tmp/b.B
46 f="_tmp/*.A"
47 echo "[ $f ]"
48 ## stdout: [ _tmp/*.A ]
49
50 #### glob after "$@" expansion
51 fun() {
52 echo "$@"
53 }
54 fun '_tmp/*.B'
55 ## stdout: _tmp/*.B
56
57 #### glob after $@ expansion
58 fun() {
59 echo $@
60 }
61 fun '_tmp/*.B'
62 ## stdout: _tmp/b.B
63
64 #### no glob after ~ expansion
65 HOME=*
66 echo ~/*.py
67 ## stdout: */*.py
68
69 #### store literal globs in array then expand
70 touch _tmp/a.A _tmp/aa.A _tmp/b.B
71 g=("_tmp/*.A" "_tmp/*.B")
72 echo ${g[@]}
73 ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B
74 ## N-I dash/ash stdout-json: ""
75 ## N-I dash/ash status: 2
76
77 #### glob inside array
78 touch _tmp/a.A _tmp/aa.A _tmp/b.B
79 g=(_tmp/*.A _tmp/*.B)
80 echo "${g[@]}"
81 ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B
82 ## N-I dash/ash stdout-json: ""
83 ## N-I dash/ash status: 2
84
85 #### glob with escaped - in char class
86 touch _tmp/foo.-
87 touch _tmp/c.C
88 echo _tmp/*.[C-D] _tmp/*.[C\-D]
89 ## stdout: _tmp/c.C _tmp/c.C _tmp/foo.-
90
91 #### glob with char class expression
92 # note: mksh doesn't support [[:punct:]] ?
93 touch _tmp/e.E _tmp/foo.-
94 echo _tmp/*.[[:punct:]E]
95 ## stdout: _tmp/e.E _tmp/foo.-
96 ## BUG mksh stdout: _tmp/*.[[:punct:]E]
97
98 #### glob double quotes
99 # note: mksh doesn't support [[:punct:]] ?
100 touch _tmp/\"quoted.py\"
101 echo _tmp/\"*.py\"
102 ## stdout: _tmp/"quoted.py"
103
104 #### glob escaped
105 # - mksh doesn't support [[:punct:]] ?
106 # - python shell fails because \[ not supported!
107 touch _tmp/\[abc\] _tmp/\?
108 echo _tmp/\[???\] _tmp/\?
109 ## stdout: _tmp/[abc] _tmp/?
110
111 #### : escaped
112 touch _tmp/foo.-
113 echo _tmp/*.[[:punct:]] _tmp/*.[[:punct\:]]
114 ## stdout: _tmp/foo.- _tmp/*.[[:punct:]]
115 ## BUG mksh stdout: _tmp/*.[[:punct:]] _tmp/*.[[:punct:]]
116 ## BUG ash stdout: _tmp/foo.- _tmp/foo.-
117
118 #### Redirect to glob, not evaluated
119 # This writes to *.F, not foo.F
120 rm _tmp/*.F
121 touch _tmp/f.F
122 echo foo > _tmp/*.F
123 cat '_tmp/*.F'
124 ## status: 0
125 ## stdout: foo
126 ## BUG bash status: 1
127 ## BUG bash stdout-json: ""
128
129 #### Glob after var manipulation
130 touch _tmp/foo.zzz _tmp/bar.zzz
131 g='_tmp/*.zzzZ'
132 echo $g ${g%Z}
133 ## stdout: _tmp/*.zzzZ _tmp/bar.zzz _tmp/foo.zzz
134
135 #### Glob after part joining
136 touch _tmp/foo.yyy _tmp/bar.yyy
137 g='_tmp/*.yy'
138 echo $g ${g}y
139 ## stdout: _tmp/*.yy _tmp/bar.yyy _tmp/foo.yyy
140
141 #### Glob flags on file system
142 touch _tmp/-n _tmp/zzzzz
143 cd _tmp
144 echo -* hello zzzz?
145 ## stdout-json: "hello zzzzz"
146
147 #### set -o noglob
148 touch _tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz
149 echo _tmp/spec-tmp/*.zz
150 set -o noglob
151 echo _tmp/spec-tmp/*.zz
152 ## stdout-json: "_tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz\n_tmp/spec-tmp/*.zz\n"
153
154 #### set -o noglob (bug #698)
155 var='\z'
156 set -f
157 echo $var
158 ## STDOUT:
159 \z
160 ## END
161
162 #### shopt -s nullglob
163 argv.py _tmp/spec-tmp/*.nonexistent
164 shopt -s nullglob
165 argv.py _tmp/spec-tmp/*.nonexistent
166 ## stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n[]\n"
167 ## N-I dash/mksh/ash stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n['_tmp/spec-tmp/*.nonexistent']\n"
168
169 #### shopt -s failglob in command context
170 argv.py *.ZZ
171 shopt -s failglob
172 argv.py *.ZZ # nothing is printed, not []
173 echo status=$?
174 ## STDOUT:
175 ['*.ZZ']
176 status=1
177 ## END
178 ## N-I dash/mksh/ash STDOUT:
179 ['*.ZZ']
180 ['*.ZZ']
181 status=0
182 ## END
183
184 #### shopt -s failglob in loop context
185 for x in *.ZZ; do echo $x; done
186 echo status=$?
187 shopt -s failglob
188 for x in *.ZZ; do echo $x; done
189 echo status=$?
190 ## STDOUT:
191 *.ZZ
192 status=0
193 status=1
194 ## END
195 ## N-I dash/mksh/ash STDOUT:
196 *.ZZ
197 status=0
198 *.ZZ
199 status=0
200 ## END
201
202 #### Don't glob flags on file system with GLOBIGNORE
203 # This is a bash-specific extension.
204 expr $0 : '.*/osh$' >/dev/null && exit 99 # disabled until cd implemented
205 touch _tmp/-n _tmp/zzzzz
206 cd _tmp # this fail in osh
207 GLOBIGNORE=-*:zzzzz # colon-separated pattern list
208 echo -* hello zzzz?
209 ## stdout-json: "-* hello zzzz?\n"
210 ## N-I dash/mksh/ash stdout-json: "hello zzzzz"
211 ## status: 0
212
213 #### Splitting/Globbing doesn't happen on local assignment
214 f() {
215 # Dash splits words and globs before handing it to the 'local' builtin. But
216 # ash doesn't!
217 local foo=$1
218 echo "$foo"
219 }
220 f 'void *'
221 ## stdout: void *
222 ## BUG dash stdout-json: ""
223 ## BUG dash status: 2
224
225 #### Glob of unescaped [[] and []]
226 touch $TMP/[ $TMP/]
227 cd $TMP
228 echo [\[z] [\]z] # the right way to do it
229 echo [[z] []z] # also accepted
230 ## STDOUT:
231 [ ]
232 [ ]
233 ## END
234
235 #### Glob of negated unescaped [[] and []]
236 # osh does this "correctly" because it defers to libc!
237 touch $TMP/_G
238 cd $TMP
239 echo _[^\[z] _[^\]z] # the right way to do it
240 echo _[^[z] _[^]z] # also accepted
241 ## STDOUT:
242 _G _G
243 _G _G
244 ## END
245 ## BUG dash/mksh STDOUT:
246 _[^[z] _[^]z]
247 _[^[z] _[^]z]
248 ## END
249
250 #### PatSub of unescaped [[] and []]
251 x='[foo]'
252 echo ${x//[\[z]/<} # the right way to do it
253 echo ${x//[\]z]/>}
254 echo ${x//[[z]/<} # also accepted
255 echo ${x//[]z]/>}
256 ## STDOUT:
257 <foo]
258 [foo>
259 <foo]
260 [foo>
261 ## END
262 ## N-I dash stdout-json: ""
263 ## N-I dash status: 2
264
265 #### PatSub of negated unescaped [[] and []]
266 x='[foo]'
267 echo ${x//[^\[z]/<} # the right way to do it
268 echo ${x//[^\]z]/>}
269 echo ${x//[^[z]/<} # also accepted
270 #echo ${x//[^]z]/>} # only busybox ash interprets as ^\]
271 ## STDOUT:
272 [<<<<
273 >>>>]
274 [<<<<
275 ## END
276 # mksh is doing something very odd, ignoring ^ altogether?
277 ## BUG mksh STDOUT:
278 <foo]
279 [foo>
280 <foo]
281 ## END
282 ## N-I dash stdout-json: ""
283 ## N-I dash status: 2
284
285 #### Glob unicode char
286
287 touch $TMP/__a__
288 touch $TMP/__μ__
289 cd $TMP
290
291 echo __?__
292
293 ## STDOUT:
294 __a__ __μ__
295 ## END
296 ## BUG dash/mksh/ash STDOUT:
297 __a__
298 ## END
299 # note: zsh also passes this, but it doesn't run with this file.
300
301 #### dotglob (bash option that dashglob is roughly consistent with)
302 mkdir -p $TMP/dotglob
303 cd $TMP/dotglob
304 touch .foorc other
305
306 echo *
307 shopt -s dotglob
308 echo *
309 ## STDOUT:
310 other
311 .foorc other
312 ## END
313 ## N-I dash/mksh/ash STDOUT:
314 other
315 other
316 ## END
317