1 #!/usr/bin/env bash
2 #
3 # Test combination of var ops.
4 #
5 # NOTE: There are also slice tests in {array,arith-context}.test.sh.
6
7 #### String length
8 v=foo
9 echo ${#v}
10 ## stdout: 3
11
12 #### Unicode string length (UTF-8)
13 v=$'_\u03bc_'
14 echo ${#v}
15 ## stdout: 3
16 ## N-I dash stdout: 9
17 ## N-I mksh stdout: 4
18
19 #### Unicode string length (spec/testdata/utf8-chars.txt)
20 v=$(cat spec/testdata/utf8-chars.txt)
21 echo ${#v}
22 ## stdout: 7
23 ## N-I dash stdout: 13
24 ## N-I mksh stdout: 13
25
26 #### String length with incomplete utf-8
27 for num_bytes in 0 1 2 3 4 5 6 7 8 9 10 11 12 13; do
28 s=$(head -c $num_bytes spec/testdata/utf8-chars.txt)
29 echo ${#s}
30 done
31 ## STDOUT:
32 0
33 1
34 2
35 error: Incomplete utf-8
36 3
37 4
38 error: Incomplete utf-8
39 error: Incomplete utf-8
40 5
41 6
42 error: Incomplete utf-8
43 error: Incomplete utf-8
44 error: Incomplete utf-8
45 7
46 ## END
47 ## BUG bash STDOUT:
48 0
49 1
50 2
51 3
52 3
53 4
54 5
55 6
56 5
57 6
58 7
59 8
60 9
61 7
62 ## END
63 ## N-I dash/mksh STDOUT:
64 0
65 1
66 2
67 3
68 4
69 5
70 6
71 7
72 8
73 9
74 10
75 11
76 12
77 13
78 ## END
79
80 #### String length with invalid utf-8 continuation bytes
81 for num_bytes in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do
82 s=$(head -c $num_bytes spec/testdata/utf8-chars.txt)$(echo -e "\xFF")
83 echo ${#s}
84 done
85 ## STDOUT:
86 error: Invalid start of utf-8 char
87 error: Invalid start of utf-8 char
88 error: Invalid start of utf-8 char
89 error: Invalid utf-8 continuation byte
90 error: Invalid start of utf-8 char
91 error: Invalid start of utf-8 char
92 error: Invalid utf-8 continuation byte
93 error: Invalid utf-8 continuation byte
94 error: Invalid start of utf-8 char
95 error: Invalid start of utf-8 char
96 error: Invalid utf-8 continuation byte
97 error: Invalid utf-8 continuation byte
98 error: Invalid utf-8 continuation byte
99 error: Invalid start of utf-8 char
100 error: Invalid start of utf-8 char
101 ## END
102 ## BUG bash STDOUT:
103 1
104 2
105 3
106 4
107 4
108 5
109 6
110 7
111 6
112 7
113 8
114 9
115 10
116 8
117 8
118 ## N-I dash STDOUT:
119 7
120 8
121 9
122 10
123 11
124 12
125 13
126 14
127 15
128 16
129 17
130 18
131 19
132 20
133 20
134 ## END
135 ## N-I mksh STDOUT:
136 1
137 2
138 3
139 4
140 5
141 6
142 7
143 8
144 9
145 10
146 11
147 12
148 13
149 14
150 14
151 ## END
152
153 #### Length of undefined variable
154 echo ${#undef}
155 ## stdout: 0
156
157 #### Length of undefined variable with nounset
158 set -o nounset
159 echo ${#undef}
160 ## status: 1
161 ## OK dash status: 2
162
163 #### Cannot take length of substring slice
164 # These are runtime errors, but we could make them parse time errors.
165 v=abcde
166 echo ${#v:1:3}
167 ## status: 1
168 ## OK osh status: 2
169 ## N-I dash status: 0
170 ## N-I dash stdout: 5
171
172 #### Pattern replacement
173 v=abcde
174 echo ${v/c*/XX}
175 ## stdout: abXX
176 ## N-I dash status: 2
177 ## N-I dash stdout-json: ""
178
179 #### Pattern replacement on unset variable
180 echo [${v/x/y}]
181 echo status=$?
182 set -o nounset # make sure this fails
183 echo [${v/x/y}]
184 ## STDOUT:
185 []
186 status=0
187 ## BUG mksh STDOUT:
188 # patsub disrespects nounset!
189 []
190 status=0
191 []
192 ## status: 1
193 ## BUG mksh status: 0
194 ## N-I dash status: 2
195 ## N-I dash stdout-json: ""
196
197 #### Global Pattern replacement with /
198 s=xx_xx_xx
199 echo ${s/xx?/yy_} ${s//xx?/yy_}
200 ## stdout: yy_xx_xx yy_yy_xx
201 ## N-I dash status: 2
202 ## N-I dash stdout-json: ""
203
204 #### Left Anchored Pattern replacement with #
205 s=xx_xx_xx
206 echo ${s/?xx/_yy} ${s/#?xx/_yy}
207 ## stdout: xx_yy_xx xx_xx_xx
208 ## N-I dash status: 2
209 ## N-I dash stdout-json: ""
210
211 #### Right Anchored Pattern replacement with %
212 s=xx_xx_xx
213 echo ${s/?xx/_yy} ${s/%?xx/_yy}
214 ## stdout: xx_yy_xx xx_xx_yy
215 ## N-I dash status: 2
216 ## N-I dash stdout-json: ""
217
218 #### Replace fixed strings
219 s=xx_xx
220 echo ${s/xx/yy} ${s//xx/yy} ${s/#xx/yy} ${s/%xx/yy}
221 ## stdout: yy_xx yy_yy yy_xx xx_yy
222 ## N-I dash status: 2
223 ## N-I dash stdout-json: ""
224
225 #### Replace is longest match
226 # If it were shortest, then you would just replace the first <html>
227 s='begin <html></html> end'
228 echo ${s/<*>/[]}
229 ## stdout: begin [] end
230 ## N-I dash status: 2
231 ## N-I dash stdout-json: ""
232
233 #### Replace char class
234 s=xx_xx_xx
235 echo ${s//[[:alpha:]]/y} ${s//[^[:alpha:]]/-}
236 ## stdout: yy_yy_yy xx-xx-xx
237 ## N-I mksh stdout: xx_xx_xx xx_xx_xx
238 ## N-I dash status: 2
239 ## N-I dash stdout-json: ""
240
241 #### Replace hard glob
242 s='aa*bb+cc'
243 echo ${s//\**+/__} # Literal *, then any sequence of characters, then literal +
244 ## stdout: aa__cc
245 ## N-I dash status: 2
246 ## N-I dash stdout-json: ""
247
248 #### Pattern replacement ${v/} is not valid
249 v=abcde
250 echo -${v/}-
251 echo status=$?
252 ## status: 2
253 ## stdout-json: ""
254 ## N-I dash status: 2
255 ## N-I dash stdout-json: ""
256 ## BUG bash/mksh status: 0
257 ## BUG bash/mksh stdout-json: "-abcde-\nstatus=0\n"
258
259 #### Pattern replacement ${v//} is not valid
260 v='a/b/c'
261 echo -${v//}-
262 echo status=$?
263 ## status: 2
264 ## stdout-json: ""
265 ## N-I dash status: 2
266 ## N-I dash stdout-json: ""
267 ## BUG bash/mksh status: 0
268 ## BUG bash/mksh stdout-json: "-a/b/c-\nstatus=0\n"
269
270 #### ${v/a} is the same as ${v/a/} -- no replacement string
271 v='aabb'
272 echo ${v/a}
273 echo status=$?
274 ## stdout-json: "abb\nstatus=0\n"
275 ## N-I dash stdout-json: ""
276 ## N-I dash status: 2
277
278 #### String slice
279 foo=abcdefg
280 echo ${foo:1:3}
281 ## stdout: bcd
282 ## N-I dash status: 2
283 ## N-I dash stdout-json: ""
284
285 #### Negative string slice
286 foo=abcdefg
287 echo ${foo: -4:3}
288 ## stdout: def
289 ## N-I dash status: 2
290 ## N-I dash stdout-json: ""
291
292 #### String slice with math
293 # I think this is the $(()) language inside?
294 i=1
295 foo=abcdefg
296 echo ${foo: i-3-2 : i + 2}
297 ## stdout: def
298 ## N-I dash status: 2
299 ## N-I dash stdout-json: ""
300
301 #### Slice String with Unicode
302 # mksh slices by bytes.
303 foo='--μ--'
304 echo ${foo:1:3}
305 ## stdout: -μ-
306 ## BUG mksh stdout: -μ
307 ## N-I dash status: 2
308 ## N-I dash stdout-json: ""