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 #### patsub with single quotes and hyphen in character class (regression)
255
256 # from Crestwave's bf.bash
257
258 program='^++--hello.,world<>[]'
259 program=${program//[^'><+-.,[]']}
260 echo $program
261 ## STDOUT:
262 ++--.,<>[]
263 ## END
264 ## BUG mksh STDOUT:
265 helloworld
266 ## END
267
268 #### patsub with [^]]
269
270 # This is a PARSING divergence. In Oil we match [], rather than using POSIX
271 # rules!
272
273 pat='[^]]'
274 s='ab^cd^'
275 echo ${s//$pat/z}
276 ## STDOUT:
277 ab^cd^
278 ## END
279
280 #### patsub syntax error
281 x=fooz
282 pat='[z-a]' # Invalid range. Other shells don't catch it!
283 #pat='[a-y]'
284 echo ${x//$pat}
285 echo status=$?
286 ## stdout-json: ""
287 ## status: 1
288 ## OK bash/mksh/zsh STDOUT:
289 fooz
290 status=0
291 ## END
292 ## OK bash/mksh/zsh status: 0