1 #
2 # Test ${x/pat*/replace}
3
4 #### Pattern replacement
5 v=abcde
6 echo ${v/c*/XX}
7 ## stdout: abXX
8
9 #### Pattern replacement on unset variable
10 echo -${v/x/y}-
11 echo status=$?
12 set -o nounset # make sure this fails
13 echo -${v/x/y}-
14 ## STDOUT:
15 --
16 status=0
17 ## BUG mksh STDOUT:
18 # patsub disrespects nounset!
19 --
20 status=0
21 --
22 ## status: 1
23 ## BUG mksh status: 0
24
25 #### Global Pattern replacement with /
26 s=xx_xx_xx
27 echo ${s/xx?/yy_} ${s//xx?/yy_}
28 ## stdout: yy_xx_xx yy_yy_xx
29
30 #### Left Anchored Pattern replacement with #
31 s=xx_xx_xx
32 echo ${s/?xx/_yy} ${s/#?xx/_yy}
33 ## stdout: xx_yy_xx xx_xx_xx
34
35 #### Right Anchored Pattern replacement with %
36 s=xx_xx_xx
37 echo ${s/?xx/_yy} ${s/%?xx/_yy}
38 ## stdout: xx_yy_xx xx_xx_yy
39
40 #### Replace fixed strings
41 s=xx_xx
42 echo ${s/xx/yy} ${s//xx/yy} ${s/#xx/yy} ${s/%xx/yy}
43 ## stdout: yy_xx yy_yy yy_xx xx_yy
44
45 #### Replace is longest match
46 # If it were shortest, then you would just replace the first <html>
47 s='begin <html></html> end'
48 echo ${s/<*>/[]}
49 ## stdout: begin [] end
50
51 #### Replace char class
52 s=xx_xx_xx
53 echo ${s//[[:alpha:]]/y} ${s//[^[:alpha:]]/-}
54 ## stdout: yy_yy_yy xx-xx-xx
55 ## N-I mksh stdout: xx_xx_xx xx_xx_xx
56
57 #### Replace hard glob
58 s='aa*bb+cc'
59 echo ${s//\**+/__} # Literal *, then any sequence of characters, then literal +
60 ## stdout: aa__cc
61
62 #### Pattern replacement ${v/} is not valid
63 v=abcde
64 echo -${v/}-
65 echo status=$?
66 ## status: 2
67 ## stdout-json: ""
68 ## BUG bash/mksh/zsh status: 0
69 ## BUG bash/mksh/zsh STDOUT:
70 -abcde-
71 status=0
72 ## END
73
74 #### Pattern replacement ${v//} is not valid
75 v='a/b/c'
76 echo -${v//}-
77 echo status=$?
78 ## status: 2
79 ## stdout-json: ""
80 ## BUG bash/mksh/zsh status: 0
81 ## BUG bash/mksh/zsh STDOUT:
82 -a/b/c-
83 status=0
84 ## END
85
86 #### Confusing unquoted slash matches bash (and ash)
87 x='/_/'
88 echo ${x////c}
89 echo ${x//'/'/c}
90 ## STDOUT:
91 c_c
92 c_c
93 ## END
94 ## BUG mksh/yash STDOUT:
95 /_/
96 c_c
97 ## END
98 ## BUG zsh STDOUT:
99 /c//c_/c/
100 /_/
101 ## END
102 ## BUG ash STDOUT:
103 c_c
104 /_/
105 ## END
106
107 #### ${v/a} is the same as ${v/a/} -- no replacement string
108 v='aabb'
109 echo ${v/a}
110 echo status=$?
111 ## STDOUT:
112 abb
113 status=0
114 ## END
115
116 #### Replacement with special chars (bug fix)
117 v=xx
118 echo ${v/x/"?"}
119 ## stdout: ?x
120
121 #### Replace backslash
122 v='[\f]'
123 x='\f'
124 echo ${v/"$x"/_}
125
126 # mksh and zsh differ on this case, but this is consistent with the fact that
127 # \f as a glob means 'f', not '\f'. TODO: Warn that it's a bad glob?
128 # The canonical form is 'f'.
129 echo ${v/$x/_}
130
131 echo ${v/\f/_}
132 echo ${v/\\f/_}
133 ## STDOUT:
134 [_]
135 [\_]
136 [\_]
137 [_]
138 ## END
139 ## BUG mksh/zsh STDOUT:
140 [_]
141 [_]
142 [\_]
143 [_]
144 ## END
145
146 #### Replace right ]
147 v='--]--'
148 x=']'
149 echo ${v/"$x"/_}
150 echo ${v/$x/_}
151 ## STDOUT:
152 --_--
153 --_--
154 ## END
155
156 #### Substitute glob characters in pattern, quoted and unquoted
157 g='*'
158 v='a*b'
159 echo ${v//"$g"/-}
160 echo ${v//$g/-}
161 ## STDOUT:
162 a-b
163 -
164 ## END
165 ## BUG zsh STDOUT:
166 a-b
167 a-b
168 ## END
169
170 #### Substitute one unicode character (UTF-8)
171 export LANG='en_US.UTF-8'
172
173 s='_μ_ and _μ_'
174
175 # ? should match one char
176
177 echo ${s//_?_/foo} # all
178 echo ${s/#_?_/foo} # left
179 echo ${s/%_?_/foo} # right
180
181 ## STDOUT:
182 foo and foo
183 foo and _μ_
184 _μ_ and foo
185 ## END
186 ## BUG mksh STDOUT:
187 _μ_ and _μ_
188 _μ_ and _μ_
189 _μ_ and _μ_
190 ## END
191
192 #### Can't substitute one unicode character when LANG=C
193 export LANG='C'
194 export LC_CTYPE='C'
195
196 s='_μ_ and _μ_'
197
198 # ? should match one char
199
200 echo ${s//_?_/foo} # all
201 echo ${s/#_?_/foo} # left
202 echo ${s/%_?_/foo} # right
203
204 ## STDOUT:
205 _μ_ and _μ_
206 _μ_ and _μ_
207 _μ_ and _μ_
208 ## END
209
210 #### ${x/^} regression
211 x=abc
212 echo ${x/^}
213 echo ${x/!}
214
215 y=^^^
216 echo ${y/^}
217 echo ${y/!}
218
219 z=!!!
220 echo ${z/^}
221 echo ${z/!}
222
223 s=a^b!c
224 echo ${s/a^}
225 echo ${s/b!}
226
227 ## STDOUT:
228 abc
229 abc
230 ^^
231 ^^^
232 !!!
233 !!
234 b!c
235 a^c
236 ## END
237
238 #### \(\) in pattern (regression)
239
240 # Not extended globs
241 x='foo()'
242 echo 1 ${x//*\(\)/z}
243 echo 2 ${x//*\(\)/z}
244 echo 3 ${x//\(\)/z}
245 echo 4 ${x//*\(\)/z}
246
247 ## STDOUT:
248 1 z
249 2 z
250 3 fooz
251 4 z
252 ## END
253
254
255 #### Extended globs! (not supported in Oil)
256 shopt -s extglob
257
258 x='foo()'
259 echo ext ${x//*(foo|bar)/z}
260 echo ext "${x//*(foo|bar)/z}"
261
262 ## STDOUT:
263 ext z()
264 ext z()
265 ## END
266
267 # I don't get what bash is doing here!
268 ## BUG bash STDOUT:
269 ext zz(z)
270 ext zz(z)
271 ## END
272
273 # GlobToERE doesn't support extended globs!
274
275 ## N-I osh STDOUT:
276 ext foo()
277 ext foo()
278 ## END
279
280 #### patsub with single quotes and hyphen in character class (regression)
281
282 # from Crestwave's bf.bash
283
284 program='^++--hello.,world<>[]'
285 program=${program//[^'><+-.,[]']}
286 echo $program
287 ## STDOUT:
288 ++--.,<>[]
289 ## END
290 ## BUG mksh STDOUT:
291 helloworld
292 ## END
293
294 #### patsub with [^]]
295
296 # This is a PARSING divergence. In Oil we match [], rather than using POSIX
297 # rules!
298
299 pat='[^]]'
300 s='ab^cd^'
301 echo ${s//$pat/z}
302 ## STDOUT:
303 ab^cd^
304 ## END
305
306 #### patsub syntax error
307 x=fooz
308 pat='[z-a]' # Invalid range. Other shells don't catch it!
309 #pat='[a-y]'
310 echo ${x//$pat}
311 echo status=$?
312 ## stdout-json: ""
313 ## status: 1
314 ## OK bash/mksh/zsh STDOUT:
315 fooz
316 status=0
317 ## END
318 ## OK bash/mksh/zsh status: 0