1 # spec/append.test.sh: Test +=
2
3 ## compare_shells: bash mksh zsh
4
5 #### Append string to string
6 s='abc'
7 s+=d
8 echo $s
9 ## stdout: abcd
10
11 #### Append array to array
12 a=(x y )
13 a+=(t 'u v')
14 argv.py "${a[@]}"
15 ## stdout: ['x', 'y', 't', 'u v']
16
17 #### Append string to undefined variable
18
19 s+=foo
20 echo s=$s
21
22 # bash and mksh agree that this does NOT respect set -u.
23 # I think that's a mistake, but += is a legacy construct, so let's copy it.
24
25 set -u
26
27 t+=foo
28 echo t=$t
29 t+=foo
30 echo t=$t
31 ## STDOUT:
32 s=foo
33 t=foo
34 t=foofoo
35 ## END
36
37 #### Append to array to undefined variable
38
39 y+=(c d)
40 argv.py "${y[@]}"
41 ## STDOUT:
42 ['c', 'd']
43 ## END
44
45 #### error: s+=(my array)
46 s='abc'
47 s+=(d e f)
48 argv.py "${s[@]}"
49 ## status: 0
50 ## STDOUT:
51 ['abc', 'd', 'e', 'f']
52 ## END
53
54 #### error: myarray+=s
55
56 # They treat this as implicit index 0. We disallow this on the LHS, so we will
57 # also disallow it on the RHS.
58 a=(x y )
59 a+=z
60 argv.py "${a[@]}"
61 ## status: 1
62 ## stdout-json: ""
63 ## OK bash/mksh status: 0
64 ## OK bash/mksh stdout: ['xz', 'y']
65 ## OK zsh status: 0
66 ## OK zsh stdout: ['x', 'y', 'z']
67
68 #### typeset s+=(my array)
69 typeset s='abc'
70 echo $s
71
72 typeset s+=(d e f)
73 echo status=$?
74 argv.py "${s[@]}"
75
76 ## status: 0
77 ## STDOUT:
78 abc
79 status=0
80 ['abc', 'd', 'e', 'f']
81 ## END
82 ## N-I mksh/zsh status: 1
83 ## N-I mksh/zsh stdout: abc
84 ## N-I mksh stderr: mksh: <stdin>[4]: syntax error: '(' unexpected
85 ## N-I zsh stderr: typeset: not valid in this context: s+
86
87 #### error: typeset myarray+=s
88 typeset a=(x y)
89 argv.py "${a[@]}"
90 typeset a+=s
91 argv.py "${a[@]}"
92
93 ## status: 1
94 ## STDOUT:
95 ['x', 'y']
96 ## END
97 ## BUG bash status: 0
98 ## BUG bash STDOUT:
99 ['x', 'y']
100 ['xs', 'y']
101 ## END
102 ## N-I mksh STDOUT:
103 ## END
104
105 #### error: append used like env prefix
106 # This should be an error in other shells but it's not.
107 A=a
108 A+=a printenv.py A
109 ## status: 2
110 ## BUG bash/zsh status: 0
111 ## BUG bash/zsh stdout: aa
112 ## BUG mksh status: 0
113 ## BUG mksh stdout: a
114
115 #### myarray[1]+=s - Append to element
116 # They treat this as implicit index 0. We disallow this on the LHS, so we will
117 # also disallow it on the RHS.
118 a=(x y )
119 a[1]+=z
120 argv.py "${a[@]}"
121 ## status: 0
122 ## stdout: ['x', 'yz']
123 ## BUG zsh stdout: ['xz', 'y']
124
125 #### myarray[-1]+=s - Append to last element
126 # Works in bash, but not mksh. It seems like bash is doing the right thing.
127 # a[-1] is allowed on the LHS. mksh doesn't have negative indexing?
128 a=(1 '2 3')
129 a[-1]+=' 4'
130 argv.py "${a[@]}"
131 ## stdout: ['1', '2 3 4']
132 ## BUG mksh stdout: ['1', '2 3', ' 4']
133
134 #### Try to append list to element
135 # bash - runtime error: cannot assign list to array number
136 # mksh - a[-1]+: is not an identifier
137 # osh - parse error -- could be better!
138 a=(1 '2 3')
139 a[-1]+=(4 5)
140 argv.py "${a[@]}"
141
142 ## stdout-json: ""
143 ## status: 2
144
145 ## OK bash status: 0
146 ## OK bash STDOUT:
147 ['1', '2 3']
148 ## END
149
150 ## OK zsh status: 0
151 ## OK zsh STDOUT:
152 ['1', '2 3', '4', '5']
153 ## END
154
155 ## N-I mksh status: 1
156
157 #### Strings have value semantics, not reference semantics
158 s1='abc'
159 s2=$s1
160 s1+='d'
161 echo $s1 $s2
162 ## stdout: abcd abc
163
164 #### typeset s+=
165
166 typeset s+=foo
167 echo s=$s
168
169 # bash and mksh agree that this does NOT respect set -u.
170 # I think that's a mistake, but += is a legacy construct, so let's copy it.
171
172 set -u
173
174 typeset t+=foo
175 echo t=$t
176 typeset t+=foo
177 echo t=$t
178 ## STDOUT:
179 s=foo
180 t=foo
181 t=foofoo
182 ## END
183 ## N-I zsh status: 1
184 ## N-I zsh stdout-json: ""
185
186 #### typeset s${dyn}+=
187
188 dyn=x
189
190 typeset s${dyn}+=foo
191 echo sx=$sx
192
193 # bash and mksh agree that this does NOT respect set -u.
194 # I think that's a mistake, but += is a legacy construct, so let's copy it.
195
196 set -u
197
198 typeset t${dyn}+=foo
199 echo tx=$tx
200 typeset t${dyn}+=foo
201 echo tx=$tx
202 ## STDOUT:
203 sx=foo
204 tx=foo
205 tx=foofoo
206 ## END
207 ## N-I zsh status: 1
208 ## N-I zsh stdout-json: ""
209
210 #### export readonly +=
211
212 export e+=foo
213 echo e=$e
214
215 readonly r+=bar
216 echo r=$r
217
218 set -u
219
220 export e+=foo
221 echo e=$e
222
223 #readonly r+=foo
224 #echo r=$e
225
226 ## STDOUT:
227 e=foo
228 r=bar
229 e=foofoo
230 ## END
231 ## N-I zsh status: 1
232 ## N-I zsh stdout-json: ""
233
234 #### local +=
235
236 f() {
237 local s+=foo
238 echo s=$s
239
240 set -u
241 local s+=foo
242 echo s=$s
243 }
244
245 f
246 ## STDOUT:
247 s=foo
248 s=foofoo
249 ## END
250 ## N-I zsh status: 1
251 ## N-I zsh stdout-json: ""
252
253 #### assign builtin appending array: declare d+=(d e)
254
255 declare d+=(d e)
256 echo "${d[@]}"
257 declare d+=(c l)
258 echo "${d[@]}"
259
260 readonly r+=(r e)
261 echo "${r[@]}"
262 # can't do this again
263
264 f() {
265 local l+=(l o)
266 echo "${l[@]}"
267
268 local l+=(c a)
269 echo "${l[@]}"
270 }
271
272 f
273
274 ## STDOUT:
275 d e
276 d e c l
277 r e
278 l o
279 l o c a
280 ## END
281 ## N-I mksh status: 1
282 ## N-I mksh stdout-json: ""
283 ## N-I zsh status: 1
284 ## N-I zsh stdout-json: ""
285
286 #### export+=array disallowed (strict_array)
287 shopt -s strict_array
288
289 export e+=(e x)
290 echo "${e[@]}"
291
292 ## status: 1
293 ## STDOUT:
294 ## END
295 ## N-I bash status: 0
296 ## N-I bash STDOUT:
297 e x
298 ## END
299
300
301 #### Type mismatching of lhs+=rhs should not cause a crash
302 case $SH in mksh|zsh) exit ;; esac
303 s=
304 a=()
305 declare -A d=([lemon]=yellow)
306
307 s+=(1)
308 s+=([melon]=green)
309
310 a+=lime
311 a+=([1]=banana)
312
313 d+=orange
314 d+=(0)
315
316 true
317
318 ## STDOUT:
319 ## END
320
321 ## OK osh status: 1
322
323 ## N-I mksh/zsh STDOUT:
324 ## END