OILS / spec / builtin-printf.test.sh View on Github | oilshell.org

1284 lines, 689 significant
1## oils_failures_allowed: 0
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
19printf
20## status: 2
21## OK mksh/zsh status: 1
22## stdout-json: ""
23
24#### printf -v %s
25var=foo
26printf -v $var %s 'hello there'
27argv.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
39val='"quoted" with spaces and \'
40
41# quote 'val' and store it in foo
42printf -v foo %q "$val"
43# then round trip back to eval
44eval "bar=$foo"
45
46# debugging:
47#echo foo="$foo"
48#echo bar="$bar"
49#echo val="$val"
50
51test "$bar" = "$val" && echo OK
52## STDOUT:
53OK
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]
61a=(a b c)
62printf -v 'a[1]' %s 'foo'
63echo status=$?
64argv.py "${a[@]}"
65## STDOUT:
66status=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
77printf -v 'a[' %s 'foo'
78echo status=$?
79## STDOUT:
80status=2
81## END
82## N-I ash/mksh/zsh stdout: -vstatus=0
83
84#### dynamic declare instead of %s
85var=foo
86declare $var='hello there'
87argv.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
96var=foo
97val='"quoted" with spaces and \'
98# I think this is bash 4.4 only.
99declare $var="${val@Q}"
100echo "$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
114case $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}
118dollar='dollar'
119f() {
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}
126echo dollar=$dollar
127echo --
128f
129echo --
130echo dollar=$dollar
131echo mylocal=$mylocal
132## STDOUT:
133dollar=dollar
134--
135dollar=\$
136mylocal=mylocal
137--
138dollar=\$
139mylocal=
140## END
141## OK osh STDOUT:
142dollar=dollar
143--
144dollar='$'
145mylocal=mylocal
146--
147dollar='$'
148mylocal=
149## END
150## N-I dash/ash/mksh/zsh STDOUT:
151not implemented
152## END
153
154#### printf with too few arguments
155printf -- '-%s-%s-%s-\n' 'a b' 'x y'
156## STDOUT:
157-a b-x y--
158## END
159
160#### printf with too many arguments
161printf -- '-%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
169printf '[%5s]\n' abc
170printf '[%-5s]\n' abc
171## STDOUT:
172[ abc]
173[abc ]
174## END
175
176#### printf integer
177printf '%d\n' 42
178printf '%i\n' 42 # synonym
179printf '%d\n' \'a # if first character is a quote, use character code
180printf '%d\n' \"a # double quotes work too
181printf '[%5d]\n' 42
182printf '[%-5d]\n' 42
183printf '[%05d]\n' 42
184#printf '[%-05d]\n' 42 # the leading 0 is meaningless
185#[42 ]
186## STDOUT:
18742
18842
18997
19097
191[ 42]
192[42 ]
193[00042]
194## END
195
196#### printf %6.4d -- "precision" does padding for integers
197printf '[%6.4d]\n' 42
198printf '[%.4d]\n' 42
199printf '[%6.d]\n' 42
200echo --
201printf '[%6.4d]\n' -42
202printf '[%.4d]\n' -42
203printf '[%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
215printf '[%6.4x]\n' 42
216printf '[%.4x]\n' 42
217printf '[%6.x]\n' 42
218echo --
219printf '[%6.4X]\n' 42
220printf '[%.4X]\n' 42
221printf '[%6.X]\n' 42
222echo --
223printf '[%6.4o]\n' 42
224printf '[%.4o]\n' 42
225printf '[%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
241printf '[%06d]\n' 42
242printf '[%06d]\n' -42 # 6 TOTAL
243echo --
244printf '[%6.6d]\n' 42
245printf '[%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
255printf '[%06x]\n' 42
256printf '[%06X]\n' 42
257printf '[%06o]\n' 42
258## STDOUT:
259[00002a]
260[00002A]
261[000052]
262## END
263
264#### %06s is no-op
265printf '(%6s)\n' 42
266printf '(%6s)\n' -42
267printf '(%06s)\n' 42
268printf '(%06s)\n' -42
269echo status=$?
270## STDOUT:
271( 42)
272( -42)
273( 42)
274( -42)
275status=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
285printf '[%6s]\n' foo
286printf '[%6.4s]\n' foo
287printf '[%-6.4s]\n' foo
288printf '[%6s]\n' spam-eggs
289printf '[%6.4s]\n' spam-eggs
290printf '[%-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
301printf '[%6.0s]\n' foo
302printf '[%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
311printf '[%6.s]\n' foo
312printf '[%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)
325printf '[%*s]\n' 9 hello
326printf '[%.*s]\n' 3 hello
327printf '[%*.3s]\n' 9 hello
328printf '[%9.*s]\n' 3 hello
329printf '[%*.*s]\n' 9 3 hello
330## STDOUT:
331[ hello]
332[hel]
333[ hel]
334[ hel]
335[ hel]
336## END
337
338#### unsigned / octal / hex
339printf '[%u]\n' 42
340printf '[%o]\n' 42
341printf '[%x]\n' 42
342printf '[%X]\n' 42
343echo
344
345printf '[%X]\n' \'a # if first character is a quote, use character code
346printf '[%X]\n' \'ab # extra chars ignored
347
348## STDOUT:
349[42]
350[52]
351[2a]
352[2A]
353
354[61]
355[61]
356## END
357
358#### unsigned / octal / hex big
359
360for big in $(( 1 << 32 )) $(( (1 << 63) - 1 )); do
361 printf '[%u]\n' $big
362 printf '[%o]\n' $big
363 printf '[%x]\n' $big
364 printf '[%X]\n' $big
365 echo
366done
367
368## STDOUT:
369[4294967296]
370[40000000000]
371[100000000]
372[100000000]
373
374[9223372036854775807]
375[777777777777777777777]
376[7fffffffffffffff]
377[7FFFFFFFFFFFFFFF]
378
379## END
380
381## BUG mksh STDOUT:
382[1]
383[1]
384[1]
385[1]
386
387[2147483647]
388[17777777777]
389[7fffffff]
390[7FFFFFFF]
391
392## END
393
394#### empty string (osh is more strict)
395printf '%d\n' ''
396## OK osh stdout-json: ""
397## OK osh status: 1
398## OK ash status: 1
399## STDOUT:
4000
401## END
402
403#### No char after ' => zero code point
404
405# most shells use 0 here
406printf '%d\n' \'
407printf '%d\n' \"
408
409## OK mksh status: 1
410## STDOUT:
4110
4120
413## END
414
415#### Unicode char with '
416case $SH in mksh) echo 'weird bug'; exit ;; esac
417
418# the mu character is U+03BC
419
420printf '%x\n' \'μ
421printf '%u\n' \'μ
422printf '%o\n' \'μ
423echo
424
425u3=三
426# u4=😘
427
428printf '%x\n' \'$u3
429printf '%u\n' \'$u3
430printf '%o\n' \'$u3
431echo
432
433# mksh DOES respect unicode on the new Debian bookworm.
434# but even building the SAME SOURCE from scratch, somehow it doesn't on Ubuntu 8.
435# TBH I should probably just upgrade the mksh version.
436#
437# $ ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
438# printf: warning: : character(s) following character constant have been ignored
439# 206
440#
441# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ cat /etc/os-release
442# NAME="Ubuntu"
443# VERSION="18.04.5 LTS (Bionic Beaver)"
444# ID=ubuntu
445# ID_LIKE=debian
446# PRETTY_NAME="Ubuntu 18.04.5 LTS"
447# VERSION_ID="18.04"
448# HOME_URL="https://www.ubuntu.com/"
449# SUPPORT_URL="https://help.ubuntu.com/"
450# BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
451# PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
452# VERSION_CODENAME=bionic
453# UBUNTU_CODENAME=bionic
454# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ env|egrep 'LC|LANG'
455# LANG=en_US.UTF-8
456# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_CTYPE=C.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
457# printf: warning: : character(s) following character constant have been ignored
458# 206
459# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LANG=C.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
460# printf: warning: : character(s) following character constant have been ignored
461# 206
462# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_ALL=C.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
463# printf: warning: : character(s) following character constant have been ignored
464# 206
465# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_ALL=en_US.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
466# printf: warning: : character(s) following character constant have been ignored
467# 206
468# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_ALL=en_US.utf-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
469# printf: warning: : character(s) following character constant have been ignored
470# 206
471
472
473## STDOUT:
4743bc
475956
4761674
477
4784e09
47919977
48047011
481
482## END
483## BUG dash/ash STDOUT:
484ce
485206
486316
487
488e4
489228
490344
491
492## END
493
494## BUG mksh STDOUT:
495weird bug
496## END
497
498#### Invalid UTF-8
499
500echo bytes1
501not_utf8=$(python2 -c 'print("\xce\xce")')
502
503printf '%x\n' \'$not_utf8
504printf '%u\n' \'$not_utf8
505printf '%o\n' \'$not_utf8
506echo
507
508echo bytes2
509not_utf8=$(python2 -c 'print("\xbc\xbc")')
510printf '%x\n' \'$not_utf8
511printf '%u\n' \'$not_utf8
512printf '%o\n' \'$not_utf8
513echo
514
515# Copied from data_lang/utf8_test.cc
516
517echo overlong2
518overlong2=$(python2 -c 'print("\xC1\x81")')
519printf '%x\n' \'$overlong2
520printf '%u\n' \'$overlong2
521printf '%o\n' \'$overlong2
522echo
523
524echo overlong3
525overlong3=$(python2 -c 'print("\xE0\x81\x81")')
526printf '%x\n' \'$overlong3
527printf '%u\n' \'$overlong3
528printf '%o\n' \'$overlong3
529echo
530
531## STDOUT:
532bytes1
533ce
534206
535316
536
537bytes2
538bc
539188
540274
541
542overlong2
543c1
544193
545301
546
547overlong3
548e0
549224
550340
551
552## END
553
554
555#### Too large
556case $SH in mksh) echo 'weird bug'; exit ;; esac
557
558echo too large
559too_large=$(python2 -c 'print("\xF4\x91\x84\x91")')
560printf '%x\n' \'$too_large
561printf '%u\n' \'$too_large
562printf '%o\n' \'$too_large
563echo
564
565## STDOUT:
566too large
567111111
5681118481
5694210421
570
571## END
572
573## BUG dash/ash STDOUT:
574too large
575f4
576244
577364
578
579## END
580
581## BUG mksh STDOUT:
582weird bug
583## END
584
585# osh rejects code points that are too large for a DIFFERENT reason
586
587## OK osh STDOUT:
588too large
589f4
590244
591364
592
593## END
594
595
596#### negative numbers with unsigned / octal / hex
597printf '[%u]\n' -42
598echo status=$?
599
600printf '[%o]\n' -42
601echo status=$?
602
603printf '[%x]\n' -42
604echo status=$?
605
606printf '[%X]\n' -42
607echo status=$?
608
609## STDOUT:
610[18446744073709551574]
611status=0
612[1777777777777777777726]
613status=0
614[ffffffffffffffd6]
615status=0
616[FFFFFFFFFFFFFFD6]
617status=0
618## END
619
620# osh DISALLOWS this because the output depends on the machine architecture.
621## N-I osh STDOUT:
622status=1
623status=1
624status=1
625status=1
626## END
627
628#### printf floating point (not required, but they all implement it)
629printf '[%f]\n' 3.14159
630printf '[%.2f]\n' 3.14159
631printf '[%8.2f]\n' 3.14159
632printf '[%-8.2f]\n' 3.14159
633printf '[%-f]\n' 3.14159
634printf '[%-f]\n' 3.14
635## STDOUT:
636[3.141590]
637[3.14]
638[ 3.14]
639[3.14 ]
640[3.141590]
641[3.140000]
642## END
643## N-I osh stdout-json: ""
644## N-I osh status: 2
645
646#### printf floating point with - and 0
647printf '[%8.4f]\n' 3.14
648printf '[%08.4f]\n' 3.14
649printf '[%8.04f]\n' 3.14 # meaning less 0
650printf '[%08.04f]\n' 3.14
651echo ---
652# these all boil down to the same thing. The -, 8, and 4 are respected, but
653# none of the 0 are.
654printf '[%-8.4f]\n' 3.14
655printf '[%-08.4f]\n' 3.14
656printf '[%-8.04f]\n' 3.14
657printf '[%-08.04f]\n' 3.14
658## STDOUT:
659[ 3.1400]
660[003.1400]
661[ 3.1400]
662[003.1400]
663---
664[3.1400 ]
665[3.1400 ]
666[3.1400 ]
667[3.1400 ]
668## END
669## N-I osh STDOUT:
670---
671## END
672## N-I osh status: 2
673
674#### printf eE fF gG
675printf '[%e]\n' 3.14
676printf '[%E]\n' 3.14
677printf '[%f]\n' 3.14
678# bash is the only one that implements %F? Is it a synonym?
679#printf '[%F]\n' 3.14
680printf '[%g]\n' 3.14
681printf '[%G]\n' 3.14
682## STDOUT:
683[3.140000e+00]
684[3.140000E+00]
685[3.140000]
686[3.14]
687[3.14]
688## END
689## N-I osh stdout-json: ""
690## N-I osh status: 2
691
692#### printf backslash escapes
693argv.py "$(printf 'a\tb')"
694argv.py "$(printf '\xE2\x98\xA0')"
695argv.py "$(printf '\044e')"
696argv.py "$(printf '\0377')" # out of range
697## STDOUT:
698['a\tb']
699['\xe2\x98\xa0']
700['$e']
701['\x1f7']
702## END
703## N-I dash STDOUT:
704['a\tb']
705['\\xE2\\x98\\xA0']
706['$e']
707['\x1f7']
708## END
709
710#### printf octal backslash escapes
711argv.py "$(printf '\0377')"
712argv.py "$(printf '\377')"
713## STDOUT:
714['\x1f7']
715['\xff']
716## END
717
718#### printf unicode backslash escapes
719argv.py "$(printf '\u2620')"
720argv.py "$(printf '\U0000065f')"
721## STDOUT:
722['\xe2\x98\xa0']
723['\xd9\x9f']
724## END
725## N-I dash/ash STDOUT:
726['\\u2620']
727['\\U0000065f']
728## END
729
730#### printf invalid backslash escape (is ignored)
731printf '[\Z]\n'
732## STDOUT:
733[\Z]
734## END
735
736#### printf % escapes
737printf '[%%]\n'
738## STDOUT:
739[%]
740## END
741
742#### printf %b backslash escaping
743printf '[%s]\n' '\044' # escapes not evaluated
744printf '[%b]\n' '\044' # YES, escapes evaluated
745echo status=$?
746## STDOUT:
747[\044]
748[$]
749status=0
750## END
751
752#### printf %b with \c early return
753printf '[%b]\n' 'ab\ncd\cxy'
754echo $?
755## STDOUT:
756[ab
757cd0
758## END
759
760#### printf %c -- doesn't respect UTF-8! Bad.
761twomu=$'\u03bc\u03bc'
762printf '[%s]\n' "$twomu"
763printf '%c' "$twomu" | wc --bytes
764## STDOUT:
765[μμ]
7661
767## END
768## N-I dash STDOUT:
769[$\u03bc\u03bc]
7701
771## END
772## N-I ash STDOUT:
773[\u03bc\u03bc]
7741
775## END
776## N-I osh STDOUT:
777[μμ]
7780
779## END
780
781#### printf invalid format
782printf '%z' 42
783echo status=$?
784printf '%-z' 42
785echo status=$?
786## STDOUT:
787status=1
788status=1
789## END
790# osh emits parse errors
791## OK dash/osh STDOUT:
792status=2
793status=2
794## END
795
796#### printf %q
797x='a b'
798printf '[%q]\n' "$x"
799## STDOUT:
800['a b']
801## END
802## OK bash/zsh STDOUT:
803[a\ b]
804## END
805## N-I ash/dash stdout-json: "["
806## N-I ash status: 1
807## N-I dash status: 2
808
809#### printf %6q (width)
810# NOTE: coreutils /usr/bin/printf does NOT implement this %6q !!!
811x='a b'
812printf '[%6q]\n' "$x"
813printf '[%1q]\n' "$x"
814## STDOUT:
815[ 'a b']
816['a b']
817## END
818## OK bash/zsh STDOUT:
819[ a\ b]
820[a\ b]
821## END
822## N-I mksh/ash/dash stdout-json: "[["
823## N-I mksh/ash status: 1
824## N-I dash status: 2
825
826#### printf negative numbers
827printf '[%d] ' -42
828echo status=$?
829printf '[%i] ' -42
830echo status=$?
831
832# extra LEADING space too
833printf '[%d] ' ' -42'
834echo status=$?
835printf '[%i] ' ' -42'
836echo status=$?
837
838# extra TRAILING space too
839printf '[%d] ' ' -42 '
840echo status=$?
841printf '[%i] ' ' -42 '
842echo status=$?
843
844# extra TRAILING chars
845printf '[%d] ' ' -42z'
846echo status=$?
847printf '[%i] ' ' -42z'
848echo status=$?
849
850exit 0 # ok
851
852## STDOUT:
853[-42] status=0
854[-42] status=0
855[-42] status=0
856[-42] status=0
857[-42] status=1
858[-42] status=1
859[-42] status=1
860[-42] status=1
861## END
862# zsh is LESS STRICT
863## OK zsh STDOUT:
864[-42] status=0
865[-42] status=0
866[-42] status=0
867[-42] status=0
868[-42] status=0
869[-42] status=0
870[0] status=1
871[0] status=1
872## END
873
874# osh is like zsh but has a hard failure (TODO: could be an option?)
875## OK osh STDOUT:
876[-42] status=0
877[-42] status=0
878[-42] status=0
879[-42] status=0
880[-42] status=0
881[-42] status=0
882status=1
883status=1
884## END
885
886# ash is MORE STRICT
887## OK ash STDOUT:
888[-42] status=0
889[-42] status=0
890[-42] status=0
891[-42] status=0
892[0] status=1
893[0] status=1
894[0] status=1
895[0] status=1
896## END
897
898
899#### printf + and space flags
900# I didn't know these existed -- I only knew about - and 0 !
901printf '[%+d]\n' 42
902printf '[%+d]\n' -42
903printf '[% d]\n' 42
904printf '[% d]\n' -42
905## STDOUT:
906[+42]
907[-42]
908[ 42]
909[-42]
910## END
911## N-I osh stdout-json: ""
912## N-I osh status: 2
913
914#### printf # flag
915# I didn't know these existed -- I only knew about - and 0 !
916# Note: '#' flag for integers outputs a prefix ONLY WHEN the value is non-zero
917printf '[%#o][%#o]\n' 0 42
918printf '[%#x][%#x]\n' 0 42
919printf '[%#X][%#X]\n' 0 42
920echo ---
921# Note: '#' flag for %f, %g always outputs the decimal point.
922printf '[%.0f][%#.0f]\n' 3 3
923# Note: In addition, '#' flag for %g does not omit zeroes in fraction
924printf '[%g][%#g]\n' 3 3
925## STDOUT:
926[0][052]
927[0][0x2a]
928[0][0X2A]
929---
930[3][3.]
931[3][3.00000]
932## END
933## N-I osh STDOUT:
934---
935## END
936## N-I osh status: 2
937
938#### Runtime error for invalid integer
939x=3abc
940printf '%d\n' $x
941echo status=$?
942printf '%d\n' xyz
943echo status=$?
944## STDOUT:
9453
946status=1
9470
948status=1
949## END
950# zsh should exit 1 in both cases
951## BUG zsh STDOUT:
9520
953status=1
9540
955status=0
956## END
957# fails but also prints 0 instead of 3abc
958## BUG ash STDOUT:
9590
960status=1
9610
962status=1
963## END
964# osh doesn't print anything invalid
965## OK osh STDOUT:
966status=1
967status=1
968## END
969
970#### %(strftime format)T
971# The result depends on timezone
972export TZ=Asia/Tokyo
973printf '%(%Y-%m-%d)T\n' 1557978599
974export TZ=US/Eastern
975printf '%(%Y-%m-%d)T\n' 1557978599
976echo status=$?
977## STDOUT:
9782019-05-16
9792019-05-15
980status=0
981## END
982## N-I mksh/zsh/ash STDOUT:
983status=1
984## END
985## N-I dash STDOUT:
986status=2
987## END
988
989#### %(strftime format)T doesn't respect TZ if not exported
990
991# note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
992
993TZ=Portugal # NOT exported
994localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
995
996# TZ is respected
997export TZ=Portugal
998tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
999
1000#echo $localtime
1001#echo $tz
1002
1003if ! test "$localtime" = "$tz"; then
1004 echo 'not equal'
1005fi
1006## STDOUT:
1007not equal
1008## END
1009## N-I mksh/zsh/ash/dash stdout-json: ""
1010
1011#### %(strftime format)T TZ in environ but not in shell's memory
1012
1013# note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
1014
1015# TZ is respected
1016export TZ=Portugal
1017tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
1018
1019unset TZ # unset in the shell, but still in the environment
1020
1021localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
1022
1023if ! test "$localtime" = "$tz"; then
1024 echo 'not equal'
1025fi
1026
1027## STDOUT:
1028not equal
1029## END
1030## N-I mksh/zsh/ash/dash stdout-json: ""
1031
1032#### %10.5(strftime format)T
1033# The result depends on timezone
1034export TZ=Asia/Tokyo
1035printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
1036export TZ=US/Eastern
1037printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
1038echo status=$?
1039## STDOUT:
1040[ 2019-]
1041[ 2019-]
1042status=0
1043## END
1044## N-I dash/mksh/zsh/ash STDOUT:
1045[[status=1
1046## END
1047## N-I dash STDOUT:
1048[[status=2
1049## END
1050
1051#### Regression for 'printf x y'
1052printf x y
1053printf '%s\n' z
1054## STDOUT:
1055xz
1056## END
1057
1058#### bash truncates long strftime string at 128
1059
1060case $SH in (ash|dash|mksh|zsh) exit ;; esac
1061
1062strftime-format() {
1063 local n=$1
1064
1065 # Prints increasingly long format strings:
1066 # %(%Y)T %(%Y)T %(%Y%Y)T ...
1067
1068 echo -n '%('
1069 for i in $(seq $n); do
1070 echo -n '%Y'
1071 done
1072 echo -n ')T'
1073}
1074
1075printf $(strftime-format 1) | wc --bytes
1076printf $(strftime-format 10) | wc --bytes
1077printf $(strftime-format 30) | wc --bytes
1078printf $(strftime-format 31) | wc --bytes
1079printf $(strftime-format 32) | wc --bytes
1080
1081case $SH in
1082 (*/_bin/cxx-dbg/*)
1083 # Ensure that oils-for-unix detects the truncation of a fixed buffer.
1084 # bash has a buffer of 128.
1085
1086 set +o errexit
1087 (
1088 printf $(strftime-format 1000)
1089 )
1090 status=$?
1091 if test $status -ne 1; then
1092 echo FAIL
1093 fi
1094 ;;
1095esac
1096
1097## STDOUT:
10984
109940
1100120
1101124
11020
1103## END
1104## OK osh STDOUT:
11054
110640
1107120
1108124
1109128
1110## END
1111
1112## N-I ash/dash/mksh/zsh STDOUT:
1113## END
1114
1115
1116#### printf with explicit NUL byte
1117case $SH in (dash|ash) return ;; esac
1118
1119printf $'x\U0z'
1120
1121printf $'\U0z'
1122
1123## stdout-json: "x"
1124## OK zsh stdout-repr: "x\0z\0z"
1125## N-I dash/ash stdout-json: ""
1126
1127#### printf positive integer overflow
1128
1129# %i seems like a synonym for %d
1130
1131for fmt in '%u\n' '%d\n'; do
1132 # bash considers this in range for %u
1133 # same with mksh
1134 # zsh cuts everything off after 19 digits
1135 # ash truncates everything
1136 printf "$fmt" '18446744073709551615'
1137 echo status=$?
1138 printf "$fmt" '18446744073709551616'
1139 echo status=$?
1140 echo
1141done
1142
1143## STDOUT:
1144status=1
1145status=1
1146
1147status=1
1148status=1
1149
1150## END
1151
1152## OK bash status: 0
1153## OK bash STDOUT:
115418446744073709551615
1155status=0
115618446744073709551615
1157status=0
1158
11599223372036854775807
1160status=0
11619223372036854775807
1162status=0
1163
1164## END
1165
1166## OK dash/mksh status: 0
1167## OK dash/mksh STDOUT:
116818446744073709551615
1169status=0
117018446744073709551615
1171status=1
1172
11739223372036854775807
1174status=1
11759223372036854775807
1176status=1
1177
1178## END
1179
1180## BUG ash status: 0
1181## BUG ash STDOUT:
118218446744073709551615
1183status=0
11840
1185status=1
1186
11870
1188status=1
11890
1190status=1
1191
1192## END
1193
1194## BUG zsh status: 0
1195## BUG zsh STDOUT:
11961844674407370955161
1197status=0
11981844674407370955161
1199status=0
1200
12011844674407370955161
1202status=0
12031844674407370955161
1204status=0
1205
1206## END
1207
1208#### printf negative integer overflow
1209
1210# %i seems like a synonym for %d
1211
1212for fmt in '%u\n' '%d\n'; do
1213
1214 printf "$fmt" '-18446744073709551615'
1215 echo status=$?
1216 printf "$fmt" '-18446744073709551616'
1217 echo status=$?
1218 echo
1219done
1220
1221## STDOUT:
1222status=1
1223status=1
1224
1225status=1
1226status=1
1227
1228## END
1229
1230## OK bash status: 0
1231## OK bash STDOUT:
12321
1233status=0
123418446744073709551615
1235status=0
1236
1237-9223372036854775808
1238status=0
1239-9223372036854775808
1240status=0
1241
1242## END
1243
1244## OK dash/mksh status: 0
1245## OK dash/mksh STDOUT:
12461
1247status=0
124818446744073709551615
1249status=1
1250
1251-9223372036854775808
1252status=1
1253-9223372036854775808
1254status=1
1255
1256## END
1257
1258## BUG zsh status: 0
1259## BUG zsh STDOUT:
126016602069666338596455
1261status=0
126216602069666338596455
1263status=0
1264
1265-1844674407370955161
1266status=0
1267-1844674407370955161
1268status=0
1269
1270## END
1271
1272## BUG ash status: 0
1273## BUG ash STDOUT:
12740
1275status=1
12760
1277status=1
1278
12790
1280status=1
12810
1282status=1
1283
1284## END