OILS / spec / word-split.test.sh View on Github | oilshell.org

421 lines, 203 significant
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
8IFS=b
9word=abcd
10f() { local IFS=c; argv.py $word; }
11f
12argv.py $word
13## stdout-json: "['ab', 'd']\n['a', 'cd']\n"
14
15#### Tilde sub is not split, but var sub is
16HOME="foo bar"
17argv.py ~
18argv.py $HOME
19## stdout-json: "['foo bar']\n['foo', 'bar']\n"
20
21#### Word splitting
22a="1 2"
23b="3 4"
24argv.py $a"$b"
25## stdout-json: "['1', '23 4']\n"
26
27#### Word splitting 2
28a="1 2"
29b="3 4"
30c="5 6"
31d="7 8"
32argv.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#### $*
39fun() { argv.py -$*-; }
40fun "a 1" "b 2" "c 3"
41## stdout: ['-a', '1', 'b', '2', 'c', '3-']
42
43#### "$*"
44fun() { argv.py "-$*-"; }
45fun "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.
50fun() { argv.py -$@-; }
51fun "a 1" "b 2" "c 3"
52## stdout: ['-a', '1', 'b', '2', 'c', '3-']
53
54#### "$@"
55fun() { argv.py "-$@-"; }
56fun "a 1" "b 2" "c 3"
57## stdout: ['-a 1', 'b 2', 'c 3-']
58
59#### empty argv
60argv.py 1 "$@" 2 $@ 3 "$*" 4 $* 5
61## stdout: ['1', '2', '3', '', '4', '5']
62
63#### Word elision with space
64s1=' '
65argv.py $s1
66## stdout: []
67
68#### Word elision with non-whitespace IFS
69# Treated differently than the default IFS. What is the rule here?
70IFS='_'
71char='_'
72space=' '
73empty=''
74argv.py $char
75argv.py $space
76argv.py $empty
77## STDOUT:
78['']
79[' ']
80[]
81## END
82
83#### Leading/trailing word elision with non-whitespace IFS
84# This behavior is weird.
85IFS=_
86s1='_a_b_'
87argv.py $s1
88## stdout: ['', 'a', 'b']
89
90#### Leading ' ' vs leading ' _ '
91# This behavior is weird, but all shells agree.
92IFS='_ '
93s1='_ a b _ '
94s2=' a b _ '
95argv.py $s1
96argv.py $s2
97## STDOUT:
98['', 'a', 'b']
99['a', 'b']
100## END
101
102#### Multiple non-whitespace IFS chars.
103IFS=_-
104s1='a__b---c_d'
105argv.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.
110IFS='_ '
111s1='a_b _ _ _ c _d e'
112argv.py $s1
113## stdout: ['a', 'b', '', '', 'c', 'd', 'e']
114
115#### empty $@ and $* is elided
116fun() { argv.py 1 $@ $* 2; }
117fun
118## stdout: ['1', '2']
119
120#### unquoted empty arg is elided
121empty=""
122argv.py 1 $empty 2
123## stdout: ['1', '2']
124
125#### unquoted whitespace arg is elided
126space=" "
127argv.py 1 $space 2
128## stdout: ['1', '2']
129
130#### empty literals are not elided
131space=" "
132argv.py 1 $space"" 2
133## stdout: ['1', '', '2']
134
135#### no splitting when IFS is empty
136IFS=""
137foo="a b"
138argv.py $foo
139## stdout: ['a b']
140
141#### default value can yield multiple words
142argv.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
146argv.py 1${undefined:-"2 3" "4 5"}6
147## stdout: ['12 3', '4 56']
148
149#### default value with unquoted IFS char
150IFS=_
151argv.py 1${undefined:-"2_3"x_x"4_5"}6
152## stdout: ['12_3x', 'x4_56']
153
154#### IFS empty doesn't do splitting
155IFS=''
156x=$(echo -e ' a b\tc\n')
157argv.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'
167unset IFS
168x=$(echo -e ' a b\tc\n')
169argv.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!
179IFS='\'
180s='a\b'
181argv.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.
189IFS='\ '
190s='a\b \\ c d\'
191argv.py $s
192## STDOUT:
193['a', 'b', '', 'c', 'd']
194## END
195
196#### IFS characters are glob metacharacters
197IFS='* '
198s='a*b c'
199argv.py $s
200
201IFS='?'
202s='?x?y?z?'
203argv.py $s
204
205IFS='['
206s='[x[y[z['
207argv.py $s
208## STDOUT:
209['a', 'b', 'c']
210['', 'x', 'y', 'z']
211['', 'x', 'y', 'z']
212## END
213
214#### Trailing space
215argv.py 'Xec ho '
216argv.py X'ec ho '
217argv.py X"ec ho "
218## STDOUT:
219['Xec ho ']
220['Xec ho ']
221['Xec ho ']
222## END
223
224#### Empty IFS (regression for bug)
225IFS=
226echo ["$*"]
227set a b c
228echo ["$*"]
229## STDOUT:
230[]
231[abc]
232## END
233
234#### Unset IFS (regression for bug)
235set a b c
236unset IFS
237echo ["$*"]
238## STDOUT:
239[a b c]
240## END
241
242#### IFS=o (regression for bug)
243IFS=o
244echo hi
245## STDOUT:
246hi
247## END
248
249#### IFS and joining arrays
250IFS=:
251set -- x 'y z'
252argv.py "$@"
253argv.py $@
254argv.py "$*"
255argv.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
264IFS=:
265set -- x 'y z'
266
267s="$@"
268argv.py "$s"
269
270s=$@
271argv.py "$s"
272
273s"$*"
274argv.py "$s"
275
276s=$*
277argv.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
310empty=""
311space=" "
312AB="A B"
313X="X"
314Yspaces=" Y "
315
316
317#### IFS='' with $@ and $* (bug #627)
318set -- a 'b c'
319IFS=''
320argv.py at $@
321argv.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)
334set -- a 'b c'
335IFS=''
336printf '[%s]\n' $@
337printf '[%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)
350myarray=(a 'b c')
351IFS=''
352argv.py at ${myarray[@]}
353argv.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
363IFS=':'
364word='a:'
365argv.py ${word}:b
366argv.py ${word}:
367
368echo ---
369
370# Same thing happens for 'z'
371IFS='z'
372word='az'
373argv.py ${word}zb
374argv.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
384var='\'
385set -f
386echo $var
387## STDOUT:
388\
389## END
390
391#### Bug #1664, \\ with noglob
392
393# Note that we're not changing IFS
394
395argv.py [\\]_
396argv.py "[\\]_"
397
398# TODO: no difference observed here, go back to original bug
399
400#argv.py [\\_
401#argv.py "[\\_"
402
403echo noglob
404
405# repeat cases with -f, noglob
406set -f
407
408argv.py [\\]_
409argv.py "[\\]_"
410
411#argv.py [\\_
412#argv.py "[\\_"
413
414## STDOUT:
415['[\\]_']
416['[\\]_']
417noglob
418['[\\]_']
419['[\\]_']
420## END
421