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