1 ## compare_shells: bash dash mksh
2 ## oils_failures_allowed: 8
3
4 # NOTE on bash bug: After setting IFS to array, it never splits anymore? Even
5 # if you assign IFS again.
6
7 #### IFS is scoped
8 IFS=b
9 word=abcd
10 f() { local IFS=c; argv.py $word; }
11 f
12 argv.py $word
13 ## stdout-json: "['ab', 'd']\n['a', 'cd']\n"
14
15 #### Tilde sub is not split, but var sub is
16 HOME="foo bar"
17 argv.py ~
18 argv.py $HOME
19 ## stdout-json: "['foo bar']\n['foo', 'bar']\n"
20
21 #### Word splitting
22 a="1 2"
23 b="3 4"
24 argv.py $a"$b"
25 ## stdout-json: "['1', '23 4']\n"
26
27 #### Word splitting 2
28 a="1 2"
29 b="3 4"
30 c="5 6"
31 d="7 8"
32 argv.py $a"$b"$c"$d"
33 ## stdout-json: "['1', '23 45', '67 8']\n"
34
35 # Has tests on differences between $* "$*" $@ "$@"
36 # http://stackoverflow.com/questions/448407/bash-script-to-receive-and-repass-quoted-parameters
37
38 #### $*
39 fun() { argv.py -$*-; }
40 fun "a 1" "b 2" "c 3"
41 ## stdout: ['-a', '1', 'b', '2', 'c', '3-']
42
43 #### "$*"
44 fun() { argv.py "-$*-"; }
45 fun "a 1" "b 2" "c 3"
46 ## stdout: ['-a 1 b 2 c 3-']
47
48 #### $@
49 # How does this differ from $* ? I don't think it does.
50 fun() { argv.py -$@-; }
51 fun "a 1" "b 2" "c 3"
52 ## stdout: ['-a', '1', 'b', '2', 'c', '3-']
53
54 #### "$@"
55 fun() { argv.py "-$@-"; }
56 fun "a 1" "b 2" "c 3"
57 ## stdout: ['-a 1', 'b 2', 'c 3-']
58
59 #### empty argv
60 argv.py 1 "$@" 2 $@ 3 "$*" 4 $* 5
61 ## stdout: ['1', '2', '3', '', '4', '5']
62
63 #### Word elision with space
64 s1=' '
65 argv.py $s1
66 ## stdout: []
67
68 #### Word elision with non-whitespace IFS
69 # Treated differently than the default IFS. What is the rule here?
70 IFS='_'
71 char='_'
72 space=' '
73 empty=''
74 argv.py $char
75 argv.py $space
76 argv.py $empty
77 ## STDOUT:
78 ['']
79 [' ']
80 []
81 ## END
82
83 #### Leading/trailing word elision with non-whitespace IFS
84 # This behavior is weird.
85 IFS=_
86 s1='_a_b_'
87 argv.py $s1
88 ## stdout: ['', 'a', 'b']
89
90 #### Leading ' ' vs leading ' _ '
91 # This behavior is weird, but all shells agree.
92 IFS='_ '
93 s1='_ a b _ '
94 s2=' a b _ '
95 argv.py $s1
96 argv.py $s2
97 ## STDOUT:
98 ['', 'a', 'b']
99 ['a', 'b']
100 ## END
101
102 #### Multiple non-whitespace IFS chars.
103 IFS=_-
104 s1='a__b---c_d'
105 argv.py $s1
106 ## stdout: ['a', '', 'b', '', '', 'c', 'd']
107
108 #### IFS with whitespace and non-whitepace.
109 # NOTE: Three delimiters means two empty words in the middle. No elision.
110 IFS='_ '
111 s1='a_b _ _ _ c _d e'
112 argv.py $s1
113 ## stdout: ['a', 'b', '', '', 'c', 'd', 'e']
114
115 #### empty $@ and $* is elided
116 fun() { argv.py 1 $@ $* 2; }
117 fun
118 ## stdout: ['1', '2']
119
120 #### unquoted empty arg is elided
121 empty=""
122 argv.py 1 $empty 2
123 ## stdout: ['1', '2']
124
125 #### unquoted whitespace arg is elided
126 space=" "
127 argv.py 1 $space 2
128 ## stdout: ['1', '2']
129
130 #### empty literals are not elided
131 space=" "
132 argv.py 1 $space"" 2
133 ## stdout: ['1', '', '2']
134
135 #### no splitting when IFS is empty
136 IFS=""
137 foo="a b"
138 argv.py $foo
139 ## stdout: ['a b']
140
141 #### default value can yield multiple words
142 argv.py 1 ${undefined:-"2 3" "4 5"} 6
143 ## stdout: ['1', '2 3', '4 5', '6']
144
145 #### default value can yield multiple words with part joining
146 argv.py 1${undefined:-"2 3" "4 5"}6
147 ## stdout: ['12 3', '4 56']
148
149 #### default value with unquoted IFS char
150 IFS=_
151 argv.py 1${undefined:-"2_3"x_x"4_5"}6
152 ## stdout: ['12_3x', 'x4_56']
153
154 #### IFS empty doesn't do splitting
155 IFS=''
156 x=$(echo -e ' a b\tc\n')
157 argv.py $x
158 ## STDOUT:
159 [' a b\tc']
160 ## END
161 ## N-I dash STDOUT:
162 ['-e a b\tc']
163 ## END
164
165
166 #### IFS unset behaves like $' \t\n'
167 unset IFS
168 x=$(echo -e ' a b\tc\n')
169 argv.py $x
170 ## STDOUT:
171 ['a', 'b', 'c']
172 ## END
173 ## N-I dash STDOUT:
174 ['-e', 'a', 'b', 'c']
175 ## END
176
177 #### IFS='\'
178 # NOTE: OSH fails this because of double backslash escaping issue!
179 IFS='\'
180 s='a\b'
181 argv.py $s
182 ## STDOUT:
183 ['a', 'b']
184 ## END
185
186 #### IFS='\ '
187 # NOTE: OSH fails this because of double backslash escaping issue!
188 # When IFS is \, then you're no longer using backslash escaping.
189 IFS='\ '
190 s='a\b \\ c d\'
191 argv.py $s
192 ## STDOUT:
193 ['a', 'b', '', 'c', 'd']
194 ## END
195
196 #### IFS characters are glob metacharacters
197 IFS='* '
198 s='a*b c'
199 argv.py $s
200
201 IFS='?'
202 s='?x?y?z?'
203 argv.py $s
204
205 IFS='['
206 s='[x[y[z['
207 argv.py $s
208 ## STDOUT:
209 ['a', 'b', 'c']
210 ['', 'x', 'y', 'z']
211 ['', 'x', 'y', 'z']
212 ## END
213
214 #### Trailing space
215 argv.py 'Xec ho '
216 argv.py X'ec ho '
217 argv.py X"ec ho "
218 ## STDOUT:
219 ['Xec ho ']
220 ['Xec ho ']
221 ['Xec ho ']
222 ## END
223
224 #### Empty IFS (regression for bug)
225 IFS=
226 echo ["$*"]
227 set a b c
228 echo ["$*"]
229 ## STDOUT:
230 []
231 [abc]
232 ## END
233
234 #### Unset IFS (regression for bug)
235 set a b c
236 unset IFS
237 echo ["$*"]
238 ## STDOUT:
239 [a b c]
240 ## END
241
242 #### IFS=o (regression for bug)
243 IFS=o
244 echo hi
245 ## STDOUT:
246 hi
247 ## END
248
249 #### IFS and joining arrays
250 IFS=:
251 set -- x 'y z'
252 argv.py "$@"
253 argv.py $@
254 argv.py "$*"
255 argv.py $*
256 ## STDOUT:
257 ['x', 'y z']
258 ['x', 'y z']
259 ['x:y z']
260 ['x', 'y z']
261 ## END
262
263 #### IFS and joining arrays by assignments
264 IFS=:
265 set -- x 'y z'
266
267 s="$@"
268 argv.py "$s"
269
270 s=$@
271 argv.py "$s"
272
273 s"$*"
274 argv.py "$s"
275
276 s=$*
277 argv.py "$s"
278
279 # bash and mksh agree, but this doesn't really make sense to me.
280 # In OSH, "$@" is the only real array, so that's why it behaves differently.
281
282 ## STDOUT:
283 ['x y z']
284 ['x y z']
285 ['x y z']
286 ['x:y z']
287 ## END
288 ## OK dash STDOUT:
289 ['x:y z']
290 ['x:y z']
291 ['x:y z']
292 ['x:y z']
293 ## END
294
295
296 # TODO:
297 # - unquoted args of whitespace are not elided (when IFS = null)
298 # - empty quoted args are kept
299 #
300 # - $* $@ with empty IFS
301 # - $* $@ with custom IFS
302 #
303 # - no splitting when IFS is empty
304 # - word splitting removes leading and trailing whitespace
305
306 # TODO: test framework needs common setup
307
308 # Test IFS and $@ $* on all these
309 #### TODO
310 empty=""
311 space=" "
312 AB="A B"
313 X="X"
314 Yspaces=" Y "
315
316
317 #### IFS='' with $@ and $* (bug #627)
318 set -- a 'b c'
319 IFS=''
320 argv.py at $@
321 argv.py star $*
322
323 # zsh agrees
324 ## STDOUT:
325 ['at', 'a', 'b c']
326 ['star', 'a', 'b c']
327 ## END
328 ## BUG ash STDOUT:
329 ['at', 'ab c']
330 ['star', 'ab c']
331 ## END
332
333 #### IFS='' with $@ and $* and printf (bug #627)
334 set -- a 'b c'
335 IFS=''
336 printf '[%s]\n' $@
337 printf '[%s]\n' $*
338 ## STDOUT:
339 [a]
340 [b c]
341 [a]
342 [b c]
343 ## END
344 ## BUG ash STDOUT:
345 [ab c]
346 [ab c]
347 ## END
348
349 #### IFS='' with ${a[@]} and ${a[*]} (bug #627)
350 myarray=(a 'b c')
351 IFS=''
352 argv.py at ${myarray[@]}
353 argv.py star ${myarray[*]}
354
355 ## STDOUT:
356 ['at', 'a', 'b c']
357 ['star', 'a', 'b c']
358 ## END
359 ## N-I dash/ash status: 2
360 ## N-I dash/ash stdout-json: ""
361
362 #### Bug #628 split on : with : in literal word
363 IFS=':'
364 word='a:'
365 argv.py ${word}:b
366 argv.py ${word}:
367
368 echo ---
369
370 # Same thing happens for 'z'
371 IFS='z'
372 word='az'
373 argv.py ${word}zb
374 argv.py ${word}z
375 ## STDOUT:
376 ['a', ':b']
377 ['a', ':']
378 ---
379 ['a', 'zb']
380 ['a', 'z']
381 ## END
382
383 #### Bug #698, similar crash
384 var='\'
385 set -f
386 echo $var
387 ## STDOUT:
388 \
389 ## END
390
391 #### Bug #1664, \\ with noglob
392
393 # Note that we're not changing IFS
394
395 argv.py [\\]_
396 argv.py "[\\]_"
397
398 # TODO: no difference observed here, go back to original bug
399
400 #argv.py [\\_
401 #argv.py "[\\_"
402
403 echo noglob
404
405 # repeat cases with -f, noglob
406 set -f
407
408 argv.py [\\]_
409 argv.py "[\\]_"
410
411 #argv.py [\\_
412 #argv.py "[\\_"
413
414 ## STDOUT:
415 ['[\\]_']
416 ['[\\]_']
417 noglob
418 ['[\\]_']
419 ['[\\]_']
420 ## END
421