OILS / spec / var-op-patsub.test.sh View on Github | oilshell.org

399 lines, 181 significant
1#
2# Test ${x/pat*/replace}
3
4#### Pattern replacement
5v=abcde
6echo ${v/c*/XX}
7## stdout: abXX
8
9#### Pattern replacement on unset variable
10echo -${v/x/y}-
11echo status=$?
12set -o nounset # make sure this fails
13echo -${v/x/y}-
14## STDOUT:
15--
16status=0
17## BUG mksh STDOUT:
18# patsub disrespects nounset!
19--
20status=0
21--
22## status: 1
23## OK ash status: 2
24## BUG mksh status: 0
25
26#### Global Pattern replacement with /
27s=xx_xx_xx
28echo ${s/xx?/yy_} ${s//xx?/yy_}
29## stdout: yy_xx_xx yy_yy_xx
30
31#### Left Anchored Pattern replacement with #
32s=xx_xx_xx
33echo ${s/?xx/_yy} ${s/#?xx/_yy}
34## stdout: xx_yy_xx xx_xx_xx
35
36#### Right Anchored Pattern replacement with %
37s=xx_xx_xx
38echo ${s/?xx/_yy} ${s/%?xx/_yy}
39## STDOUT:
40xx_yy_xx xx_xx_yy
41## END
42## BUG ash STDOUT:
43xx_yy_xx xx_xx_xx
44## END
45
46#### Replace fixed strings
47s=xx_xx
48echo ${s/xx/yy} ${s//xx/yy} ${s/#xx/yy} ${s/%xx/yy}
49## STDOUT:
50yy_xx yy_yy yy_xx xx_yy
51## END
52## BUG ash STDOUT:
53yy_xx yy_yy xx_xx xx_xx
54## END
55
56#### Replace is longest match
57# If it were shortest, then you would just replace the first <html>
58s='begin <html></html> end'
59echo ${s/<*>/[]}
60## stdout: begin [] end
61
62#### Replace char class
63s=xx_xx_xx
64echo ${s//[[:alpha:]]/y} ${s//[^[:alpha:]]/-}
65## stdout: yy_yy_yy xx-xx-xx
66## N-I mksh stdout: xx_xx_xx xx_xx_xx
67
68#### Replace hard glob
69s='aa*bb+cc'
70echo ${s//\**+/__} # Literal *, then any sequence of characters, then literal +
71## stdout: aa__cc
72
73#### ${v/} is empty search and replacement
74v=abcde
75echo -${v/}-
76echo status=$?
77## status: 0
78## STDOUT:
79-abcde-
80status=0
81## END
82## BUG ash STDOUT:
83-abcde -
84status=0
85## END
86
87#### ${v//} is empty search and replacement
88v='a/b/c'
89echo -${v//}-
90echo status=$?
91## status: 0
92## STDOUT:
93-a/b/c-
94status=0
95## END
96## BUG ash STDOUT:
97-a/b/c -
98status=0
99## END
100
101#### Confusing unquoted slash matches bash (and ash)
102x='/_/'
103echo ${x////c}
104
105echo ${x//'/'/c}
106
107## STDOUT:
108c_c
109c_c
110## END
111## BUG mksh STDOUT:
112/_/
113c_c
114## END
115## BUG zsh STDOUT:
116/c//c_/c/
117/_/
118## END
119## BUG ash STDOUT:
120c_c
121/_/ /c
122## END
123
124#### Synthesized ${x///} bug (similar to above)
125
126# found via test/parse-errors.sh
127
128x='slash / brace } hi'
129echo 'ambiguous:' ${x///}
130
131echo 'quoted: ' ${x//'/'}
132
133# Wow we have all combination here -- TERRIBLE
134
135## STDOUT:
136ambiguous: slash brace } hi
137quoted: slash brace } hi
138## END
139## BUG mksh STDOUT:
140ambiguous: slash / brace } hi
141quoted: slash brace } hi
142## END
143## BUG zsh STDOUT:
144ambiguous: slash / brace } hi
145quoted: slash / brace } hi
146## END
147## BUG ash STDOUT:
148ambiguous: slash brace } hi
149quoted: slash / brace } hi
150## END
151
152
153#### ${v/a} is the same as ${v/a/} -- no replacement string
154v='aabb'
155echo ${v/a}
156echo status=$?
157## STDOUT:
158abb
159status=0
160## END
161
162#### Replacement with special chars (bug fix)
163v=xx
164echo ${v/x/"?"}
165## stdout: ?x
166
167#### Replace backslash
168v='[\f]'
169x='\f'
170echo ${v/"$x"/_}
171
172# mksh and zsh differ on this case, but this is consistent with the fact that
173# \f as a glob means 'f', not '\f'. TODO: Warn that it's a bad glob?
174# The canonical form is 'f'.
175echo ${v/$x/_}
176
177echo ${v/\f/_}
178echo ${v/\\f/_}
179## STDOUT:
180[_]
181[\_]
182[\_]
183[_]
184## END
185## BUG mksh/zsh STDOUT:
186[_]
187[_]
188[\_]
189[_]
190## END
191
192#### Replace right ]
193v='--]--'
194x=']'
195echo ${v/"$x"/_}
196echo ${v/$x/_}
197## STDOUT:
198--_--
199--_--
200## END
201
202#### Substitute glob characters in pattern, quoted and unquoted
203
204# INFINITE LOOP in ash!
205case $SH in ash) exit ;; esac
206
207g='*'
208v='a*b'
209echo ${v//"$g"/-}
210echo ${v//$g/-}
211## STDOUT:
212a-b
213-
214## END
215## BUG zsh STDOUT:
216a-b
217a-b
218## END
219
220#### Substitute one unicode character (UTF-8)
221export LANG='en_US.UTF-8'
222
223s='_μ_ and _μ_'
224
225# ? should match one char
226
227echo ${s//_?_/foo} # all
228echo ${s/#_?_/foo} # left
229echo ${s/%_?_/foo} # right
230
231## STDOUT:
232foo and foo
233foo and _μ_
234_μ_ and foo
235## END
236## BUG mksh STDOUT:
237_μ_ and _μ_
238_μ_ and _μ_
239_μ_ and _μ_
240## END
241
242#### Can't substitute one unicode character when LC_ALL=C
243export LC_ALL='C'
244
245s='_μ_ and _μ_'
246
247# ? should match one char
248
249echo ${s//_?_/foo} # all
250echo ${s/#_?_/foo} # left
251echo ${s/%_?_/foo} # right
252
253## STDOUT:
254_μ_ and _μ_
255_μ_ and _μ_
256_μ_ and _μ_
257## END
258
259#### ${x/^} regression
260x=abc
261echo ${x/^}
262echo ${x/!}
263
264y=^^^
265echo ${y/^}
266echo ${y/!}
267
268z=!!!
269echo ${z/^}
270echo ${z/!}
271
272s=a^b!c
273echo ${s/a^}
274echo ${s/b!}
275
276## STDOUT:
277abc
278abc
279^^
280^^^
281!!!
282!!
283b!c
284a^c
285## END
286
287#### \(\) in pattern (regression)
288
289# Not extended globs
290x='foo()'
291echo 1 ${x//*\(\)/z}
292echo 2 ${x//*\(\)/z}
293echo 3 ${x//\(\)/z}
294echo 4 ${x//*\(\)/z}
295
296## STDOUT:
2971 z
2982 z
2993 fooz
3004 z
301## END
302
303#### patsub with single quotes and hyphen in character class (regression)
304
305# from Crestwave's bf.bash
306
307program='^++--hello.,world<>[]'
308program=${program//[^'><+-.,[]']}
309echo $program
310## STDOUT:
311++--.,<>[]
312## END
313## BUG mksh STDOUT:
314helloworld
315## END
316
317#### patsub with [^]]
318
319# This is a PARSING divergence. In Oil we match [], rather than using POSIX
320# rules!
321
322pat='[^]]'
323s='ab^cd^'
324echo ${s//$pat/z}
325## STDOUT:
326ab^cd^
327## END
328
329#### [a-z] Invalid range end is syntax error
330x=fooz
331pat='[z-a]' # Invalid range. Other shells don't catch it!
332#pat='[a-y]'
333echo ${x//$pat}
334echo status=$?
335## stdout-json: ""
336## status: 1
337## OK bash/mksh/zsh/ash STDOUT:
338fooz
339status=0
340## END
341## OK bash/mksh/zsh/ash status: 0
342
343
344#### Pattern is empty $foo$bar -- regression for infinite loop
345
346x=-foo-
347
348echo ${x//$foo$bar/bar}
349
350## STDOUT:
351-foo-
352## END
353
354# feels like memory unsafety in ZSH
355## BUG zsh STDOUT:
356bar-barfbarobarobar-
357## END
358
359#### Chromium from http://www.oilshell.org/blog/2016/11/07.html
360
361case $SH in zsh) exit ;; esac
362
363HOST_PATH=/foo/bar/baz
364echo ${HOST_PATH////\\/}
365
366# The way bash parses it
367echo ${HOST_PATH//'/'/\\/}
368
369## STDOUT:
370\/foo\/bar\/baz
371\/foo\/bar\/baz
372## END
373
374# zsh has crazy bugs
375## BUG zsh stdout-json: ""
376
377## BUG mksh STDOUT:
378/foo/bar/baz
379\/foo\/bar\/baz
380## END
381
382
383#### ${x//~homedir/}
384
385path=~/git/oilshell
386
387# ~ expansion occurs
388#echo path=$path
389
390echo ${path//~/z}
391
392echo ${path/~/z}
393
394## STDOUT:
395z/git/oilshell
396z/git/oilshell
397## END
398
399