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

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