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 LC_ALL=C
193 export LC_ALL='C'
194
195 s='_μ_ and _μ_'
196
197 # ? should match one char
198
199 echo ${s//_?_/foo} # all
200 echo ${s/#_?_/foo} # left
201 echo ${s/%_?_/foo} # right
202
203 ## STDOUT:
204 _μ_ and _μ_
205 _μ_ and _μ_
206 _μ_ and _μ_
207 ## END
208
209 #### ${x/^} regression
210 x=abc
211 echo ${x/^}
212 echo ${x/!}
213
214 y=^^^
215 echo ${y/^}
216 echo ${y/!}
217
218 z=!!!
219 echo ${z/^}
220 echo ${z/!}
221
222 s=a^b!c
223 echo ${s/a^}
224 echo ${s/b!}
225
226 ## STDOUT:
227 abc
228 abc
229 ^^
230 ^^^
231 !!!
232 !!
233 b!c
234 a^c
235 ## END
236
237 #### \(\) in pattern (regression)
238
239 # Not extended globs
240 x='foo()'
241 echo 1 ${x//*\(\)/z}
242 echo 2 ${x//*\(\)/z}
243 echo 3 ${x//\(\)/z}
244 echo 4 ${x//*\(\)/z}
245
246 ## STDOUT:
247 1 z
248 2 z
249 3 fooz
250 4 z
251 ## END
252
253 #### patsub with single quotes and hyphen in character class (regression)
254
255 # from Crestwave's bf.bash
256
257 program='^++--hello.,world<>[]'
258 program=${program//[^'><+-.,[]']}
259 echo $program
260 ## STDOUT:
261 ++--.,<>[]
262 ## END
263 ## BUG mksh STDOUT:
264 helloworld
265 ## END
266
267 #### patsub with [^]]
268
269 # This is a PARSING divergence. In Oil we match [], rather than using POSIX
270 # rules!
271
272 pat='[^]]'
273 s='ab^cd^'
274 echo ${s//$pat/z}
275 ## STDOUT:
276 ab^cd^
277 ## END
278
279 #### patsub syntax error
280 x=fooz
281 pat='[z-a]' # Invalid range. Other shells don't catch it!
282 #pat='[a-y]'
283 echo ${x//$pat}
284 echo status=$?
285 ## stdout-json: ""
286 ## status: 1
287 ## OK bash/mksh/zsh STDOUT:
288 fooz
289 status=0
290 ## END
291 ## OK bash/mksh/zsh status: 0