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 cd $REPO_ROOT
19 echo [b]in
20 ## stdout: bin
21
22 #### 0 char glob -- does NOT work
23 echo []bin
24 ## stdout: []bin
25
26 #### looks like glob at the start, but isn't
27 echo [bin
28 ## stdout: [bin
29
30 #### looks like glob plus negation at the start, but isn't
31 echo [!bin
32 ## stdout: [!bin
33
34 #### glob can expand to command and arg
35 cd $REPO_ROOT
36 spec/testdata/echo.s[hz]
37 ## stdout: spec/testdata/echo.sz
38
39 #### glob after var expansion
40 touch _tmp/a.A _tmp/aa.A _tmp/b.B
41 f="_tmp/*.A"
42 g="$f _tmp/*.B"
43 echo $g
44 ## stdout: _tmp/a.A _tmp/aa.A _tmp/b.B
45
46 #### quoted var expansion with glob meta characters
47 touch _tmp/a.A _tmp/aa.A _tmp/b.B
48 f="_tmp/*.A"
49 echo "[ $f ]"
50 ## stdout: [ _tmp/*.A ]
51
52 #### glob after "$@" expansion
53 fun() {
54 echo "$@"
55 }
56 fun '_tmp/*.B'
57 ## stdout: _tmp/*.B
58
59 #### glob after $@ expansion
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 touch _tmp/foo.-
115 echo _tmp/*.[[:punct:]] _tmp/*.[[:punct\:]]
116 ## stdout: _tmp/foo.- _tmp/*.[[:punct:]]
117 ## BUG mksh stdout: _tmp/*.[[:punct:]] _tmp/*.[[:punct:]]
118 ## BUG ash stdout: _tmp/foo.- _tmp/foo.-
119
120 #### Redirect to glob, not evaluated
121 # This writes to *.F, not foo.F
122 rm _tmp/*.F
123 touch _tmp/f.F
124 echo foo > _tmp/*.F
125 cat '_tmp/*.F'
126 ## status: 0
127 ## stdout: foo
128 ## BUG bash status: 1
129 ## BUG bash stdout-json: ""
130
131 #### Glob after var manipulation
132 touch _tmp/foo.zzz _tmp/bar.zzz
133 g='_tmp/*.zzzZ'
134 echo $g ${g%Z}
135 ## stdout: _tmp/*.zzzZ _tmp/bar.zzz _tmp/foo.zzz
136
137 #### Glob after part joining
138 touch _tmp/foo.yyy _tmp/bar.yyy
139 g='_tmp/*.yy'
140 echo $g ${g}y
141 ## stdout: _tmp/*.yy _tmp/bar.yyy _tmp/foo.yyy
142
143 #### Glob flags on file system
144 touch _tmp/-n _tmp/zzzzz
145 cd _tmp
146 echo -* hello zzzz?
147 ## stdout-json: "hello zzzzz"
148
149 #### set -o noglob
150 cd $REPO_ROOT
151 touch _tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz
152 echo _tmp/spec-tmp/*.zz
153 set -o noglob
154 echo _tmp/spec-tmp/*.zz
155 ## stdout-json: "_tmp/spec-tmp/a.zz _tmp/spec-tmp/b.zz\n_tmp/spec-tmp/*.zz\n"
156
157 #### set -o noglob (bug #698)
158 var='\z'
159 set -f
160 echo $var
161 ## STDOUT:
162 \z
163 ## END
164
165 #### shopt -s nullglob
166 argv.py _tmp/spec-tmp/*.nonexistent
167 shopt -s nullglob
168 argv.py _tmp/spec-tmp/*.nonexistent
169 ## stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n[]\n"
170 ## N-I dash/mksh/ash stdout-json: "['_tmp/spec-tmp/*.nonexistent']\n['_tmp/spec-tmp/*.nonexistent']\n"
171
172 #### shopt -s failglob in command context
173 argv.py *.ZZ
174 shopt -s failglob
175 argv.py *.ZZ # nothing is printed, not []
176 echo status=$?
177 ## STDOUT:
178 ['*.ZZ']
179 status=1
180 ## END
181 ## N-I dash/mksh/ash STDOUT:
182 ['*.ZZ']
183 ['*.ZZ']
184 status=0
185 ## END
186
187 #### shopt -s failglob in loop context
188 for x in *.ZZ; do echo $x; done
189 echo status=$?
190 shopt -s failglob
191 for x in *.ZZ; do echo $x; done
192 echo status=$?
193 ## STDOUT:
194 *.ZZ
195 status=0
196 status=1
197 ## END
198 ## N-I dash/mksh/ash STDOUT:
199 *.ZZ
200 status=0
201 *.ZZ
202 status=0
203 ## END
204
205 #### Don't glob flags on file system with GLOBIGNORE
206 # This is a bash-specific extension.
207 expr $0 : '.*/osh$' >/dev/null && exit 99 # disabled until cd implemented
208 touch _tmp/-n _tmp/zzzzz
209 cd _tmp # this fail in osh
210 GLOBIGNORE=-*:zzzzz # colon-separated pattern list
211 echo -* hello zzzz?
212 ## stdout-json: "-* hello zzzz?\n"
213 ## N-I dash/mksh/ash stdout-json: "hello zzzzz"
214 ## status: 0
215
216 #### Splitting/Globbing doesn't happen on local assignment
217 cd $REPO_ROOT
218
219 f() {
220 # Dash splits words and globs before handing it to the 'local' builtin. But
221 # ash doesn't!
222 local foo=$1
223 echo "$foo"
224 }
225 f 'void *'
226 ## stdout: void *
227 ## BUG dash stdout-json: ""
228 ## BUG dash status: 2
229
230 #### Glob of unescaped [[] and []]
231 touch $TMP/[ $TMP/]
232 cd $TMP
233 echo [\[z] [\]z] # the right way to do it
234 echo [[z] []z] # also accepted
235 ## STDOUT:
236 [ ]
237 [ ]
238 ## END
239
240 #### Glob of negated unescaped [[] and []]
241 # osh does this "correctly" because it defers to libc!
242 touch $TMP/_G
243 cd $TMP
244 echo _[^\[z] _[^\]z] # the right way to do it
245 echo _[^[z] _[^]z] # also accepted
246 ## STDOUT:
247 _G _G
248 _G _G
249 ## END
250 ## BUG dash/mksh STDOUT:
251 _[^[z] _[^]z]
252 _[^[z] _[^]z]
253 ## END
254
255 #### PatSub of unescaped [[] and []]
256 x='[foo]'
257 echo ${x//[\[z]/<} # the right way to do it
258 echo ${x//[\]z]/>}
259 echo ${x//[[z]/<} # also accepted
260 echo ${x//[]z]/>}
261 ## STDOUT:
262 <foo]
263 [foo>
264 <foo]
265 [foo>
266 ## END
267 ## N-I dash stdout-json: ""
268 ## N-I dash status: 2
269
270 #### PatSub of negated unescaped [[] and []]
271 x='[foo]'
272 echo ${x//[^\[z]/<} # the right way to do it
273 echo ${x//[^\]z]/>}
274 echo ${x//[^[z]/<} # also accepted
275 #echo ${x//[^]z]/>} # only busybox ash interprets as ^\]
276 ## STDOUT:
277 [<<<<
278 >>>>]
279 [<<<<
280 ## END
281 # mksh is doing something very odd, ignoring ^ altogether?
282 ## BUG mksh STDOUT:
283 <foo]
284 [foo>
285 <foo]
286 ## END
287 ## N-I dash stdout-json: ""
288 ## N-I dash status: 2
289
290 #### Glob unicode char
291
292 touch $TMP/__a__
293 touch $TMP/__μ__
294 cd $TMP
295
296 echo __?__
297
298 ## STDOUT:
299 __a__ __μ__
300 ## END
301 ## BUG dash/mksh/ash STDOUT:
302 __a__
303 ## END
304 # note: zsh also passes this, but it doesn't run with this file.
305
306 #### dotglob (bash option that dashglob is roughly consistent with)
307 mkdir -p $TMP/dotglob
308 cd $TMP/dotglob
309 touch .foorc other
310
311 echo *
312 shopt -s dotglob
313 echo *
314 ## STDOUT:
315 other
316 .foorc other
317 ## END
318 ## N-I dash/mksh/ash STDOUT:
319 other
320 other
321 ## END
322