1 ## oils_failures_allowed: 1
2 ## compare_shells: dash bash mksh zsh ash
3
4 # printf
5 # bash-completion uses this odd printf -v construction. It seems to mostly use
6 # %s and %q though.
7 #
8 # %s should just be
9 # declare $var='val'
10 #
11 # NOTE:
12 # /usr/bin/printf %q "'" seems wrong.
13 # $ /usr/bin/printf %q "'"
14 # ''\'''
15 #
16 # I suppose it is technically correct, but it looks very ugly.
17
18 #### printf with no args
19 printf
20 ## status: 2
21 ## OK mksh/zsh status: 1
22 ## stdout-json: ""
23
24 #### printf -v %s
25 var=foo
26 printf -v $var %s 'hello there'
27 argv.py "$foo"
28 ## STDOUT:
29 ['hello there']
30 ## END
31 ## N-I mksh/zsh/ash STDOUT:
32 -v['']
33 ## END
34 ## N-I dash STDOUT:
35 ['']
36 ## END
37
38 #### printf -v %q
39 val='"quoted" with spaces and \'
40
41 # quote 'val' and store it in foo
42 printf -v foo %q "$val"
43 # then round trip back to eval
44 eval "bar=$foo"
45
46 # debugging:
47 #echo foo="$foo"
48 #echo bar="$bar"
49 #echo val="$val"
50
51 test "$bar" = "$val" && echo OK
52 ## STDOUT:
53 OK
54 ## END
55 ## N-I mksh/zsh/ash stdout-json: "-v"
56 ## N-I mksh/zsh/ash status: 1
57 ## N-I dash stdout-json: ""
58 ## N-I dash status: 1
59
60 #### printf -v a[1]
61 a=(a b c)
62 printf -v 'a[1]' %s 'foo'
63 echo status=$?
64 argv.py "${a[@]}"
65 ## STDOUT:
66 status=0
67 ['a', 'foo', 'c']
68 ## END
69 ## N-I mksh/zsh STDOUT:
70 -vstatus=0
71 ['a', 'b', 'c']
72 ## END
73 ## N-I dash/ash stdout-json: ""
74 ## N-I dash/ash status: 2
75
76 #### printf -v syntax error
77 printf -v 'a[' %s 'foo'
78 echo status=$?
79 ## STDOUT:
80 status=2
81 ## END
82 ## N-I ash/mksh/zsh stdout: -vstatus=0
83
84 #### dynamic declare instead of %s
85 var=foo
86 declare $var='hello there'
87 argv.py "$foo"
88 ## STDOUT:
89 ['hello there']
90 ## END
91 ## N-I dash/mksh/ash STDOUT:
92 ['']
93 ## END
94
95 #### dynamic declare instead of %q
96 var=foo
97 val='"quoted" with spaces and \'
98 # I think this is bash 4.4 only.
99 declare $var="${val@Q}"
100 echo "$foo"
101 ## STDOUT:
102 '"quoted" with spaces and \'
103 ## END
104 ## OK osh STDOUT:
105 $'"quoted" with spaces and \\'
106 ## END
107 ## N-I dash/ash stdout-json: ""
108 ## N-I dash/ash status: 2
109 ## N-I mksh stdout-json: "\n"
110 ## N-I zsh stdout-json: ""
111 ## N-I zsh status: 1
112
113 #### printf -v dynamic scope
114 case $SH in mksh|zsh|dash|ash) echo not implemented; exit ;; esac
115 # OK so printf is like assigning to a var.
116 # printf -v foo %q "$bar" is like
117 # foo=${bar@Q}
118 dollar='dollar'
119 f() {
120 local mylocal=foo
121 printf -v dollar %q '$' # assign foo to a quoted dollar
122 printf -v mylocal %q 'mylocal'
123 echo dollar=$dollar
124 echo mylocal=$mylocal
125 }
126 echo dollar=$dollar
127 echo --
128 f
129 echo --
130 echo dollar=$dollar
131 echo mylocal=$mylocal
132 ## STDOUT:
133 dollar=dollar
134 --
135 dollar=\$
136 mylocal=mylocal
137 --
138 dollar=\$
139 mylocal=
140 ## END
141 ## OK osh STDOUT:
142 dollar=dollar
143 --
144 dollar='$'
145 mylocal=mylocal
146 --
147 dollar='$'
148 mylocal=
149 ## END
150 ## N-I dash/ash/mksh/zsh STDOUT:
151 not implemented
152 ## END
153
154 #### printf with too few arguments
155 printf -- '-%s-%s-%s-\n' 'a b' 'x y'
156 ## STDOUT:
157 -a b-x y--
158 ## END
159
160 #### printf with too many arguments
161 printf -- '-%s-%s-\n' a b c d e
162 ## STDOUT:
163 -a-b-
164 -c-d-
165 -e--
166 ## END
167
168 #### printf width strings
169 printf '[%5s]\n' abc
170 printf '[%-5s]\n' abc
171 ## STDOUT:
172 [ abc]
173 [abc ]
174 ## END
175
176 #### printf integer
177 printf '%d\n' 42
178 printf '%i\n' 42 # synonym
179 printf '%d\n' \'a # if first character is a quote, use character code
180 printf '%d\n' \"a # double quotes work too
181 printf '[%5d]\n' 42
182 printf '[%-5d]\n' 42
183 printf '[%05d]\n' 42
184 #printf '[%-05d]\n' 42 # the leading 0 is meaningless
185 #[42 ]
186 ## STDOUT:
187 42
188 42
189 97
190 97
191 [ 42]
192 [42 ]
193 [00042]
194 ## END
195
196 #### printf %6.4d -- "precision" does padding for integers
197 printf '[%6.4d]\n' 42
198 printf '[%.4d]\n' 42
199 printf '[%6.d]\n' 42
200 echo --
201 printf '[%6.4d]\n' -42
202 printf '[%.4d]\n' -42
203 printf '[%6.d]\n' -42
204 ## STDOUT:
205 [ 0042]
206 [0042]
207 [ 42]
208 --
209 [ -0042]
210 [-0042]
211 [ -42]
212 ## END
213
214 #### printf %6.4x X o
215 printf '[%6.4x]\n' 42
216 printf '[%.4x]\n' 42
217 printf '[%6.x]\n' 42
218 echo --
219 printf '[%6.4X]\n' 42
220 printf '[%.4X]\n' 42
221 printf '[%6.X]\n' 42
222 echo --
223 printf '[%6.4o]\n' 42
224 printf '[%.4o]\n' 42
225 printf '[%6.o]\n' 42
226 ## STDOUT:
227 [ 002a]
228 [002a]
229 [ 2a]
230 --
231 [ 002A]
232 [002A]
233 [ 2A]
234 --
235 [ 0052]
236 [0052]
237 [ 52]
238 ## END
239
240 #### %06d zero padding vs. %6.6d
241 printf '[%06d]\n' 42
242 printf '[%06d]\n' -42 # 6 TOTAL
243 echo --
244 printf '[%6.6d]\n' 42
245 printf '[%6.6d]\n' -42 # 6 + 1 for the - sign!!!
246 ## STDOUT:
247 [000042]
248 [-00042]
249 --
250 [000042]
251 [-000042]
252 ## END
253
254 #### %06x %06X %06o
255 printf '[%06x]\n' 42
256 printf '[%06X]\n' 42
257 printf '[%06o]\n' 42
258 ## STDOUT:
259 [00002a]
260 [00002A]
261 [000052]
262 ## END
263
264 #### %06s is no-op
265 printf '(%6s)\n' 42
266 printf '(%6s)\n' -42
267 printf '(%06s)\n' 42
268 printf '(%06s)\n' -42
269 echo status=$?
270 ## STDOUT:
271 ( 42)
272 ( -42)
273 ( 42)
274 ( -42)
275 status=0
276 ## END
277 # mksh is stricter
278 ## OK mksh STDOUT:
279 ( 42)
280 ( -42)
281 ((status=1
282 ## END
283
284 #### printf %6.4s does both truncation and padding
285 printf '[%6s]\n' foo
286 printf '[%6.4s]\n' foo
287 printf '[%-6.4s]\n' foo
288 printf '[%6s]\n' spam-eggs
289 printf '[%6.4s]\n' spam-eggs
290 printf '[%-6.4s]\n' spam-eggs
291 ## STDOUT:
292 [ foo]
293 [ foo]
294 [foo ]
295 [spam-eggs]
296 [ spam]
297 [spam ]
298 ## END
299
300 #### printf %6.0s and %0.0s
301 printf '[%6.0s]\n' foo
302 printf '[%0.0s]\n' foo
303 ## STDOUT:
304 [ ]
305 []
306 ## END
307 ## N-I mksh stdout-json: "[ ]\n["
308 ## N-I mksh status: 1
309
310 #### printf %6.s and %0.s
311 printf '[%6.s]\n' foo
312 printf '[%0.s]\n' foo
313 ## STDOUT:
314 [ ]
315 []
316 ## END
317 ## BUG zsh STDOUT:
318 [ foo]
319 [foo]
320 ## END
321 ## N-I mksh stdout-json: "[ ]\n["
322 ## N-I mksh status: 1
323
324 #### printf %*.*s (width/precision from args)
325 printf '[%*s]\n' 9 hello
326 printf '[%.*s]\n' 3 hello
327 printf '[%*.3s]\n' 9 hello
328 printf '[%9.*s]\n' 3 hello
329 printf '[%*.*s]\n' 9 3 hello
330 ## STDOUT:
331 [ hello]
332 [hel]
333 [ hel]
334 [ hel]
335 [ hel]
336 ## END
337
338 #### unsigned / octal / hex
339 printf '[%u]\n' 42
340 printf '[%o]\n' 42
341 printf '[%x]\n' 42
342 printf '[%X]\n' 42
343 printf '[%X]\n' \'a # if first character is a quote, use character code
344 printf '[%X]\n' \'ab # extra chars ignored
345 ## STDOUT:
346 [42]
347 [52]
348 [2a]
349 [2A]
350 [61]
351 [61]
352 ## END
353
354 #### empty string (osh is more strict)
355 printf '%d\n' ''
356 ## OK osh stdout-json: ""
357 ## OK osh status: 1
358 ## OK ash status: 1
359 ## STDOUT:
360 0
361 ## END
362
363 #### No char after ' (osh is more strict)
364
365 # most shells use 0 here
366 printf '%d\n' \'
367 printf '%d\n' \"
368
369 ## OK mksh status: 1
370 ## STDOUT:
371 0
372 0
373 ## END
374
375 #### Unicode char with ' (osh is more strict)
376
377 # the mu character is U+03BC
378
379 printf '%x\n' \'μ
380
381 ## STDOUT:
382 3bc
383 ## END
384 ## BUG dash/mksh/ash STDOUT:
385 ce
386 ## END
387
388 #### negative numbers with unsigned / octal / hex
389 printf '[%u]\n' -42
390 printf '[%o]\n' -42
391 printf '[%x]\n' -42
392 printf '[%X]\n' -42
393 ## STDOUT:
394 [18446744073709551574]
395 [1777777777777777777726]
396 [ffffffffffffffd6]
397 [FFFFFFFFFFFFFFD6]
398 ## END
399
400 # osh DISALLOWS this because the output depends on the machine architecture.
401 ## N-I osh stdout-json: ""
402 ## N-I osh status: 1
403
404 #### printf floating point (not required, but they all implement it)
405 printf '[%f]\n' 3.14159
406 printf '[%.2f]\n' 3.14159
407 printf '[%8.2f]\n' 3.14159
408 printf '[%-8.2f]\n' 3.14159
409 printf '[%-f]\n' 3.14159
410 printf '[%-f]\n' 3.14
411 ## STDOUT:
412 [3.141590]
413 [3.14]
414 [ 3.14]
415 [3.14 ]
416 [3.141590]
417 [3.140000]
418 ## END
419 ## N-I osh stdout-json: ""
420 ## N-I osh status: 2
421
422 #### printf floating point with - and 0
423 printf '[%8.4f]\n' 3.14
424 printf '[%08.4f]\n' 3.14
425 printf '[%8.04f]\n' 3.14 # meaning less 0
426 printf '[%08.04f]\n' 3.14
427 echo ---
428 # these all boil down to the same thing. The -, 8, and 4 are respected, but
429 # none of the 0 are.
430 printf '[%-8.4f]\n' 3.14
431 printf '[%-08.4f]\n' 3.14
432 printf '[%-8.04f]\n' 3.14
433 printf '[%-08.04f]\n' 3.14
434 ## STDOUT:
435 [ 3.1400]
436 [003.1400]
437 [ 3.1400]
438 [003.1400]
439 ---
440 [3.1400 ]
441 [3.1400 ]
442 [3.1400 ]
443 [3.1400 ]
444 ## END
445 ## N-I osh STDOUT:
446 ---
447 ## END
448 ## N-I osh status: 2
449
450 #### printf eE fF gG
451 printf '[%e]\n' 3.14
452 printf '[%E]\n' 3.14
453 printf '[%f]\n' 3.14
454 # bash is the only one that implements %F? Is it a synonym?
455 #printf '[%F]\n' 3.14
456 printf '[%g]\n' 3.14
457 printf '[%G]\n' 3.14
458 ## STDOUT:
459 [3.140000e+00]
460 [3.140000E+00]
461 [3.140000]
462 [3.14]
463 [3.14]
464 ## END
465 ## N-I osh stdout-json: ""
466 ## N-I osh status: 2
467
468 #### printf backslash escapes
469 argv.py "$(printf 'a\tb')"
470 argv.py "$(printf '\xE2\x98\xA0')"
471 argv.py "$(printf '\044e')"
472 argv.py "$(printf '\0377')" # out of range
473 ## STDOUT:
474 ['a\tb']
475 ['\xe2\x98\xa0']
476 ['$e']
477 ['\x1f7']
478 ## END
479 ## N-I dash STDOUT:
480 ['a\tb']
481 ['\\xE2\\x98\\xA0']
482 ['$e']
483 ['\x1f7']
484 ## END
485
486 #### printf octal backslash escapes
487 argv.py "$(printf '\0377')"
488 argv.py "$(printf '\377')"
489 ## STDOUT:
490 ['\x1f7']
491 ['\xff']
492 ## END
493
494 #### printf unicode backslash escapes
495 argv.py "$(printf '\u2620')"
496 argv.py "$(printf '\U0000065f')"
497 ## STDOUT:
498 ['\xe2\x98\xa0']
499 ['\xd9\x9f']
500 ## END
501 ## N-I dash/ash STDOUT:
502 ['\\u2620']
503 ['\\U0000065f']
504 ## END
505
506 #### printf invalid backslash escape (is ignored)
507 printf '[\Z]\n'
508 ## STDOUT:
509 [\Z]
510 ## END
511
512 #### printf % escapes
513 printf '[%%]\n'
514 ## STDOUT:
515 [%]
516 ## END
517
518 #### printf %b backslash escaping
519 printf '[%s]\n' '\044' # escapes not evaluated
520 printf '[%b]\n' '\044' # YES, escapes evaluated
521 echo status=$?
522 ## STDOUT:
523 [\044]
524 [$]
525 status=0
526 ## END
527
528 #### printf %b with \c early return
529 printf '[%b]\n' 'ab\ncd\cxy'
530 echo $?
531 ## STDOUT:
532 [ab
533 cd0
534 ## END
535
536 #### printf %c -- doesn't respect UTF-8! Bad.
537 twomu=$'\u03bc\u03bc'
538 printf '[%s]\n' "$twomu"
539 printf '%c' "$twomu" | wc --bytes
540 ## STDOUT:
541 [μμ]
542 1
543 ## END
544 ## N-I dash STDOUT:
545 [$\u03bc\u03bc]
546 1
547 ## END
548 ## N-I ash STDOUT:
549 [\u03bc\u03bc]
550 1
551 ## END
552 ## N-I osh STDOUT:
553 [μμ]
554 0
555 ## END
556
557 #### printf invalid format
558 printf '%z' 42
559 echo status=$?
560 printf '%-z' 42
561 echo status=$?
562 ## STDOUT:
563 status=1
564 status=1
565 ## END
566 # osh emits parse errors
567 ## OK dash/osh STDOUT:
568 status=2
569 status=2
570 ## END
571
572 #### printf %q
573 x='a b'
574 printf '[%q]\n' "$x"
575 ## STDOUT:
576 ['a b']
577 ## END
578 ## OK bash/zsh STDOUT:
579 [a\ b]
580 ## END
581 ## N-I ash/dash stdout-json: "["
582 ## N-I ash status: 1
583 ## N-I dash status: 2
584
585 #### printf %6q (width)
586 # NOTE: coreutils /usr/bin/printf does NOT implement this %6q !!!
587 x='a b'
588 printf '[%6q]\n' "$x"
589 printf '[%1q]\n' "$x"
590 ## STDOUT:
591 [ 'a b']
592 ['a b']
593 ## END
594 ## OK bash/zsh STDOUT:
595 [ a\ b]
596 [a\ b]
597 ## END
598 ## N-I mksh/ash/dash stdout-json: "[["
599 ## N-I mksh/ash status: 1
600 ## N-I dash status: 2
601
602 #### printf negative numbers
603 printf '[%d] ' -42
604 echo status=$?
605 printf '[%i] ' -42
606 echo status=$?
607
608 # extra LEADING space too
609 printf '[%d] ' ' -42'
610 echo status=$?
611 printf '[%i] ' ' -42'
612 echo status=$?
613
614 # extra TRAILING space too
615 printf '[%d] ' ' -42 '
616 echo status=$?
617 printf '[%i] ' ' -42 '
618 echo status=$?
619
620 # extra TRAILING chars
621 printf '[%d] ' ' -42z'
622 echo status=$?
623 printf '[%i] ' ' -42z'
624 echo status=$?
625
626 exit 0 # ok
627
628 ## STDOUT:
629 [-42] status=0
630 [-42] status=0
631 [-42] status=0
632 [-42] status=0
633 [-42] status=1
634 [-42] status=1
635 [-42] status=1
636 [-42] status=1
637 ## END
638 # zsh is LESS STRICT
639 ## OK zsh STDOUT:
640 [-42] status=0
641 [-42] status=0
642 [-42] status=0
643 [-42] status=0
644 [-42] status=0
645 [-42] status=0
646 [0] status=1
647 [0] status=1
648 ## END
649
650 # osh is like zsh but has a hard failure (TODO: could be an option?)
651 ## OK osh STDOUT:
652 [-42] status=0
653 [-42] status=0
654 [-42] status=0
655 [-42] status=0
656 [-42] status=0
657 [-42] status=0
658 status=1
659 status=1
660 ## END
661
662 # ash is MORE STRICT
663 ## OK ash STDOUT:
664 [-42] status=0
665 [-42] status=0
666 [-42] status=0
667 [-42] status=0
668 [0] status=1
669 [0] status=1
670 [0] status=1
671 [0] status=1
672 ## END
673
674
675 #### printf + and space flags
676 # I didn't know these existed -- I only knew about - and 0 !
677 printf '[%+d]\n' 42
678 printf '[%+d]\n' -42
679 printf '[% d]\n' 42
680 printf '[% d]\n' -42
681 ## STDOUT:
682 [+42]
683 [-42]
684 [ 42]
685 [-42]
686 ## END
687 ## N-I osh stdout-json: ""
688 ## N-I osh status: 2
689
690 #### printf # flag
691 # I didn't know these existed -- I only knew about - and 0 !
692 # Note: '#' flag for integers outputs a prefix ONLY WHEN the value is non-zero
693 printf '[%#o][%#o]\n' 0 42
694 printf '[%#x][%#x]\n' 0 42
695 printf '[%#X][%#X]\n' 0 42
696 echo ---
697 # Note: '#' flag for %f, %g always outputs the decimal point.
698 printf '[%.0f][%#.0f]\n' 3 3
699 # Note: In addition, '#' flag for %g does not omit zeroes in fraction
700 printf '[%g][%#g]\n' 3 3
701 ## STDOUT:
702 [0][052]
703 [0][0x2a]
704 [0][0X2A]
705 ---
706 [3][3.]
707 [3][3.00000]
708 ## END
709 ## N-I osh STDOUT:
710 ---
711 ## END
712 ## N-I osh status: 2
713
714 #### Runtime error for invalid integer
715 x=3abc
716 printf '%d\n' $x
717 echo status=$?
718 printf '%d\n' xyz
719 echo status=$?
720 ## STDOUT:
721 3
722 status=1
723 0
724 status=1
725 ## END
726 # zsh should exit 1 in both cases
727 ## BUG zsh STDOUT:
728 0
729 status=1
730 0
731 status=0
732 ## END
733 # fails but also prints 0 instead of 3abc
734 ## BUG ash STDOUT:
735 0
736 status=1
737 0
738 status=1
739 ## END
740 # osh doesn't print anything invalid
741 ## OK osh STDOUT:
742 status=1
743 status=1
744 ## END
745
746 #### %(strftime format)T
747 # The result depends on timezone
748 export TZ=Asia/Tokyo
749 printf '%(%Y-%m-%d)T\n' 1557978599
750 export TZ=US/Eastern
751 printf '%(%Y-%m-%d)T\n' 1557978599
752 echo status=$?
753 ## STDOUT:
754 2019-05-16
755 2019-05-15
756 status=0
757 ## END
758 ## N-I mksh/zsh/ash STDOUT:
759 status=1
760 ## END
761 ## N-I dash STDOUT:
762 status=2
763 ## END
764
765 #### %(strftime format)T doesn't respect TZ if not exported
766
767 # note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
768
769 TZ=Portugal # NOT exported
770 localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
771
772 # TZ is respected
773 export TZ=Portugal
774 tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
775
776 #echo $localtime
777 #echo $tz
778
779 if ! test "$localtime" = "$tz"; then
780 echo 'not equal'
781 fi
782 ## STDOUT:
783 not equal
784 ## END
785 ## N-I mksh/zsh/ash/dash stdout-json: ""
786
787 #### %(strftime format)T TZ in environ but not in shell's memory
788
789 # note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
790
791 # TZ is respected
792 export TZ=Portugal
793 tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
794
795 unset TZ # unset in the shell, but still in the environment
796
797 localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
798
799 if ! test "$localtime" = "$tz"; then
800 echo 'not equal'
801 fi
802
803 ## STDOUT:
804 not equal
805 ## END
806 ## N-I mksh/zsh/ash/dash stdout-json: ""
807
808 #### %10.5(strftime format)T
809 # The result depends on timezone
810 export TZ=Asia/Tokyo
811 printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
812 export TZ=US/Eastern
813 printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
814 echo status=$?
815 ## STDOUT:
816 [ 2019-]
817 [ 2019-]
818 status=0
819 ## END
820 ## N-I dash/mksh/zsh/ash STDOUT:
821 [[status=1
822 ## END
823 ## N-I dash STDOUT:
824 [[status=2
825 ## END
826
827 #### Regression for 'printf x y'
828 printf x y
829 printf '%s\n' z
830 ## STDOUT:
831 xz
832 ## END
833
834 #### bash truncates long strftime string at 128
835
836 case $SH in (ash|dash|mksh|zsh) exit ;; esac
837
838 strftime-format() {
839 local n=$1
840
841 # Prints increasingly long format strings:
842 # %(%Y)T %(%Y)T %(%Y%Y)T ...
843
844 echo -n '%('
845 for i in $(seq $n); do
846 echo -n '%Y'
847 done
848 echo -n ')T'
849 }
850
851 printf $(strftime-format 1) | wc --bytes
852 printf $(strftime-format 10) | wc --bytes
853 printf $(strftime-format 30) | wc --bytes
854 printf $(strftime-format 31) | wc --bytes
855 printf $(strftime-format 32) | wc --bytes
856
857 case $SH in
858 (*/_bin/cxx-dbg/*)
859 # Ensure that oils-for-unix detects the truncation of a fixed buffer.
860 # bash has a buffer of 128.
861
862 set +o errexit
863 (
864 printf $(strftime-format 1000)
865 )
866 status=$?
867 if test $status -ne 1; then
868 echo FAIL
869 fi
870 ;;
871 esac
872
873 ## STDOUT:
874 4
875 40
876 120
877 124
878 0
879 ## END
880 ## OK osh STDOUT:
881 4
882 40
883 120
884 124
885 128
886 ## END
887
888 ## N-I ash/dash/mksh/zsh STDOUT:
889 ## END
890
891
892 #### printf with explicit NUL byte
893 case $SH in (dash|ash) return ;; esac
894
895 printf $'x\U0z'
896
897 printf $'\U0z'
898
899 ## stdout-json: "x"
900 ## OK zsh stdout-repr: "x\0z\0z"
901 ## N-I dash/ash stdout-json: ""