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

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