OILS / spec / nul-bytes.test.sh View on Github | oils.pub

519 lines, 263 significant
1## compare_shells: dash bash mksh zsh ash
2## oils_failures_allowed: 2
3## oils_cpp_failures_allowed: 1
4
5#### NUL bytes with echo -e
6case $SH in dash) exit ;; esac
7
8show_hex() { od -A n -t c -t x1; }
9
10echo -e '\0-' | show_hex
11#echo -e '\x00-'
12#echo -e '\000-'
13
14## STDOUT:
15 \0 - \n
16 00 2d 0a
17## END
18
19## BUG zsh STDOUT:
20 \0 \n
21 00 0a
22## END
23
24## N-I dash STDOUT:
25## END
26
27#### printf - literal NUL in format string
28case $SH in dash|ash) return ;; esac
29
30# Show both printable and hex
31show_hex() { od -A n -t c -t x1; }
32
33printf $'x\U0z' | show_hex
34echo ---
35
36printf $'x\U00z' | show_hex
37echo ---
38
39printf $'\U0z' | show_hex
40
41## STDOUT:
42 x
43 78
44---
45 x
46 78
47---
48## END
49## BUG zsh STDOUT:
50 x \0 z
51 78 00 7a
52---
53 x \0 z
54 78 00 7a
55---
56 \0 z
57 00 7a
58## END
59## N-I dash/ash STDOUT:
60## END
61
62#### printf - \0 escape shows NUL byte
63show_hex() { od -A n -t c -t x1; }
64
65printf '\0\n' | show_hex
66## STDOUT:
67 \0 \n
68 00 0a
69## END
70
71#### printf - NUL byte in value (OSH and zsh agree)
72case $SH in dash) exit ;; esac
73show_hex() { od -A n -t c -t x1; }
74
75nul=$'\0'
76echo "$nul" | show_hex
77printf '%s\n' "$nul" | show_hex
78
79## STDOUT:
80 \n
81 0a
82 \n
83 0a
84## END
85
86## OK osh/zsh STDOUT:
87 \0 \n
88 00 0a
89 \0 \n
90 00 0a
91## END
92## N-I dash stdout-json: ""
93
94#### NUL bytes with echo $'\0' (OSH and zsh agree)
95case $SH in dash) exit ;; esac
96show_hex() { od -A n -t c -t x1; }
97
98# OSH agrees with ZSH -- so you have the ability to print NUL bytes without
99# legacy echo -e
100
101echo $'\0' | show_hex
102
103## STDOUT:
104 \n
105 0a
106## END
107## OK osh/zsh STDOUT:
108 \0 \n
109 00 0a
110## END
111
112
113## N-I dash stdout-json: ""
114
115
116#### NUL bytes and IFS splitting
117case $SH in dash) exit ;; esac
118
119argv.py $(echo -e '\0')
120argv.py "$(echo -e '\0')"
121argv.py $(echo -e 'a\0b')
122argv.py "$(echo -e 'a\0b')"
123
124## STDOUT:
125[]
126['']
127['ab']
128['ab']
129## END
130## BUG zsh STDOUT:
131['', '']
132['']
133['a', 'b']
134['a']
135## END
136
137## N-I dash STDOUT:
138## END
139
140#### NUL bytes with test -n
141
142case $SH in dash) exit ;; esac
143
144# zsh is buggy here, weird
145test -n $''
146echo status=$?
147
148test -n $'\0'
149echo status=$?
150
151
152## STDOUT:
153status=1
154status=1
155## END
156## OK osh STDOUT:
157status=1
158status=0
159## END
160## BUG zsh STDOUT:
161status=0
162status=0
163## END
164
165## N-I dash STDOUT:
166## END
167
168
169#### NUL bytes with test -f
170
171case $SH in dash) exit ;; esac
172
173
174test -f $'\0'
175echo status=$?
176
177touch foo
178test -f $'foo\0'
179echo status=$?
180
181test -f $'foo\0bar'
182echo status=$?
183
184test -f $'foobar'
185echo status=$?
186
187
188## STDOUT:
189status=1
190status=0
191status=0
192status=1
193## END
194
195## OK ash STDOUT:
196status=1
197status=0
198status=1
199status=1
200## END
201
202## N-I dash STDOUT:
203## END
204
205
206#### NUL bytes with ${#s} (OSH and zsh agree)
207
208case $SH in dash) exit ;; esac
209
210empty=$''
211nul=$'\0'
212
213echo empty=${#empty}
214echo nul=${#nul}
215
216
217## STDOUT:
218empty=0
219nul=0
220## END
221
222## OK osh/zsh STDOUT:
223empty=0
224nul=1
225## END
226
227## N-I dash STDOUT:
228## END
229
230#### Compare \x00 byte versus \x01 byte - command sub
231
232# https://stackoverflow.com/questions/32722007/is-skipping-ignoring-nul-bytes-on-process-substitution-standardized
233# bash contains a warning!
234
235show_bytes() {
236 echo -n "$1" | od -A n -t x1
237}
238
239s=$(printf '.\001.')
240echo len=${#s}
241show_bytes "$s"
242
243s=$(printf '.\000.')
244echo len=${#s}
245show_bytes "$s"
246
247s=$(printf '\000')
248echo len=${#s}
249show_bytes "$s"
250
251## STDOUT:
252len=3
253 2e 01 2e
254len=2
255 2e 2e
256len=0
257## END
258
259## BUG zsh STDOUT:
260len=3
261 2e 01 2e
262len=3
263 2e 00 2e
264len=1
265 00
266## END
267
268#### Compare \x00 byte versus \x01 byte - read builtin
269
270# Hm same odd behavior
271
272show_string() {
273 read s
274 echo len=${#s}
275 echo -n "$s" | od -A n -t x1
276}
277
278printf '.\001.' | show_string
279
280printf '.\000.' | show_string
281
282printf '\000' | show_string
283
284## STDOUT:
285len=3
286 2e 01 2e
287len=2
288 2e 2e
289len=0
290## END
291
292## BUG zsh STDOUT:
293len=3
294 2e 01 2e
295len=3
296 2e 00 2e
297len=1
298 00
299## END
300
301#### Compare \x00 byte versus \x01 byte - read -n
302case $SH in dash) exit ;; esac
303
304show_string() {
305 read -n 3 s
306 echo len=${#s}
307 echo -n "$s" | od -A n -t x1
308}
309
310
311printf '.\001.' | show_string
312
313printf '.\000.' | show_string
314
315printf '\000' | show_string
316
317## STDOUT:
318len=3
319 2e 01 2e
320len=2
321 2e 2e
322len=0
323## END
324
325## BUG-2 mksh STDOUT:
326len=3
327 2e 01 2e
328len=1
329 2e
330len=0
331## END
332
333## BUG zsh STDOUT:
334len=0
335len=1
336 2e
337len=0
338## END
339
340## N-I dash STDOUT:
341## END
342
343
344#### Compare \x00 byte versus \x01 byte - mapfile builtin
345case $SH in dash|mksh|zsh|ash) exit ;; esac
346
347{
348 printf '.\000.\n'
349 printf '.\000.\n'
350} |
351{ mapfile LINES
352 echo len=${#LINES[@]}
353 for line in ${LINES[@]}; do
354 echo -n "$line" | od -A n -t x1
355 done
356}
357
358# bash is INCONSISTENT:
359# - it TRUNCATES at \0, with 'mapfile'
360# - rather than just IGNORING \0, with 'read'
361
362## STDOUT:
363len=2
364 2e
365 2e
366## END
367
368## N-I dash/mksh/zsh/ash STDOUT:
369## END
370
371#### Strip ops # ## % %% with NUL bytes
372
373show_bytes() {
374 echo -n "$1" | od -A n -t x1
375}
376
377s=$(printf '\000.\000')
378echo len=${#s}
379show_bytes "$s"
380
381echo ---
382
383t=${s#?}
384echo len=${#t}
385show_bytes "$t"
386
387t=${s##?}
388echo len=${#t}
389show_bytes "$t"
390
391t=${s%?}
392echo len=${#t}
393show_bytes "$t"
394
395t=${s%%?}
396echo len=${#t}
397show_bytes "$t"
398
399## STDOUT:
400len=1
401 2e
402---
403len=0
404len=0
405len=0
406len=0
407## END
408
409## BUG zsh STDOUT:
410len=3
411 00 2e 00
412---
413len=2
414 2e 00
415len=2
416 2e 00
417len=2
418 00 2e
419len=2
420 00 2e
421## END
422
423#### Issue 2269 Reduction
424
425show_bytes() {
426 echo -n "$1" | od -A n -t x1
427}
428
429s=$(printf '\000x')
430echo len=${#s}
431show_bytes "$s"
432
433# strip one char from the front
434s=${s#?}
435echo len=${#s}
436show_bytes "$s"
437
438echo ---
439
440s=$(printf '\001x')
441echo len=${#s}
442show_bytes "$s"
443
444# strip one char from the front
445s=${s#?}
446echo len=${#s}
447show_bytes "$s"
448
449## STDOUT:
450len=1
451 78
452len=0
453---
454len=2
455 01 78
456len=1
457 78
458## END
459
460## BUG zsh STDOUT:
461len=2
462 00 78
463len=1
464 78
465---
466len=2
467 01 78
468len=1
469 78
470## END
471
472#### Issue 2269 - Do NUL bytes match ? in ${a#?}
473
474# https://github.com/oils-for-unix/oils/issues/2269
475
476escape_arg() {
477 a="$1"
478 until [ -z "$a" ]; do
479 case "$a" in
480 (\'*) printf "'\"'\"'";;
481 (*) printf %.1s "$a";;
482 esac
483 a="${a#?}"
484 echo len=${#a} >&2
485 done
486}
487
488# encode
489phrase="$(escape_arg "that's it!")"
490echo escaped "$phrase"
491
492# decode
493eval "printf '%s\\n' '$phrase'"
494
495echo ---
496
497# harder input: NUL surrounded with ::
498arg="$(printf ':\000:')"
499#echo "arg=$arg"
500
501case $SH in
502 zsh) echo 'writes binary data' ;;
503 *) echo escaped "$(escape_arg "$arg")" ;;
504esac
505#echo "arg=$arg"
506
507## STDOUT:
508escaped that'"'"'s it!
509that's it!
510---
511escaped ::
512## END
513
514## OK zsh STDOUT:
515escaped that'"'"'s it!
516that's it!
517---
518writes binary data
519## END