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