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