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

1100 lines, 587 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 '
416#env
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/mksh STDOUT:
484ce
485206
486316
487
488e4
489228
490344
491
492## END
493
494#### Invalid UTF-8
495
496echo bytes1
497not_utf8=$(python2 -c 'print("\xce\xce")')
498
499printf '%x\n' \'$not_utf8
500printf '%u\n' \'$not_utf8
501printf '%o\n' \'$not_utf8
502echo
503
504echo bytes2
505not_utf8=$(python2 -c 'print("\xbc\xbc")')
506printf '%x\n' \'$not_utf8
507printf '%u\n' \'$not_utf8
508printf '%o\n' \'$not_utf8
509echo
510
511# Copied from data_lang/utf8_test.cc
512
513echo overlong2
514overlong2=$(python2 -c 'print("\xC1\x81")')
515printf '%x\n' \'$overlong2
516printf '%u\n' \'$overlong2
517printf '%o\n' \'$overlong2
518echo
519
520echo overlong3
521overlong3=$(python2 -c 'print("\xE0\x81\x81")')
522printf '%x\n' \'$overlong3
523printf '%u\n' \'$overlong3
524printf '%o\n' \'$overlong3
525echo
526
527## STDOUT:
528bytes1
529ce
530206
531316
532
533bytes2
534bc
535188
536274
537
538overlong2
539c1
540193
541301
542
543overlong3
544e0
545224
546340
547
548## END
549
550
551#### Too large
552
553echo too large
554too_large=$(python2 -c 'print("\xF4\x91\x84\x91")')
555printf '%x\n' \'$too_large
556printf '%u\n' \'$too_large
557printf '%o\n' \'$too_large
558echo
559
560## STDOUT:
561too large
562111111
5631118481
5644210421
565
566## END
567
568## BUG dash/ash/mksh STDOUT:
569too large
570f4
571244
572364
573
574## END
575
576# osh rejects code points that are too large for a DIFFERENT reason
577
578## OK osh STDOUT:
579too large
580f4
581244
582364
583
584## END
585
586
587#### negative numbers with unsigned / octal / hex
588printf '[%u]\n' -42
589printf '[%o]\n' -42
590printf '[%x]\n' -42
591printf '[%X]\n' -42
592## STDOUT:
593[18446744073709551574]
594[1777777777777777777726]
595[ffffffffffffffd6]
596[FFFFFFFFFFFFFFD6]
597## END
598
599# osh DISALLOWS this because the output depends on the machine architecture.
600## N-I osh stdout-json: ""
601## N-I osh status: 1
602
603#### printf floating point (not required, but they all implement it)
604printf '[%f]\n' 3.14159
605printf '[%.2f]\n' 3.14159
606printf '[%8.2f]\n' 3.14159
607printf '[%-8.2f]\n' 3.14159
608printf '[%-f]\n' 3.14159
609printf '[%-f]\n' 3.14
610## STDOUT:
611[3.141590]
612[3.14]
613[ 3.14]
614[3.14 ]
615[3.141590]
616[3.140000]
617## END
618## N-I osh stdout-json: ""
619## N-I osh status: 2
620
621#### printf floating point with - and 0
622printf '[%8.4f]\n' 3.14
623printf '[%08.4f]\n' 3.14
624printf '[%8.04f]\n' 3.14 # meaning less 0
625printf '[%08.04f]\n' 3.14
626echo ---
627# these all boil down to the same thing. The -, 8, and 4 are respected, but
628# none of the 0 are.
629printf '[%-8.4f]\n' 3.14
630printf '[%-08.4f]\n' 3.14
631printf '[%-8.04f]\n' 3.14
632printf '[%-08.04f]\n' 3.14
633## STDOUT:
634[ 3.1400]
635[003.1400]
636[ 3.1400]
637[003.1400]
638---
639[3.1400 ]
640[3.1400 ]
641[3.1400 ]
642[3.1400 ]
643## END
644## N-I osh STDOUT:
645---
646## END
647## N-I osh status: 2
648
649#### printf eE fF gG
650printf '[%e]\n' 3.14
651printf '[%E]\n' 3.14
652printf '[%f]\n' 3.14
653# bash is the only one that implements %F? Is it a synonym?
654#printf '[%F]\n' 3.14
655printf '[%g]\n' 3.14
656printf '[%G]\n' 3.14
657## STDOUT:
658[3.140000e+00]
659[3.140000E+00]
660[3.140000]
661[3.14]
662[3.14]
663## END
664## N-I osh stdout-json: ""
665## N-I osh status: 2
666
667#### printf backslash escapes
668argv.py "$(printf 'a\tb')"
669argv.py "$(printf '\xE2\x98\xA0')"
670argv.py "$(printf '\044e')"
671argv.py "$(printf '\0377')" # out of range
672## STDOUT:
673['a\tb']
674['\xe2\x98\xa0']
675['$e']
676['\x1f7']
677## END
678## N-I dash STDOUT:
679['a\tb']
680['\\xE2\\x98\\xA0']
681['$e']
682['\x1f7']
683## END
684
685#### printf octal backslash escapes
686argv.py "$(printf '\0377')"
687argv.py "$(printf '\377')"
688## STDOUT:
689['\x1f7']
690['\xff']
691## END
692
693#### printf unicode backslash escapes
694argv.py "$(printf '\u2620')"
695argv.py "$(printf '\U0000065f')"
696## STDOUT:
697['\xe2\x98\xa0']
698['\xd9\x9f']
699## END
700## N-I dash/ash STDOUT:
701['\\u2620']
702['\\U0000065f']
703## END
704
705#### printf invalid backslash escape (is ignored)
706printf '[\Z]\n'
707## STDOUT:
708[\Z]
709## END
710
711#### printf % escapes
712printf '[%%]\n'
713## STDOUT:
714[%]
715## END
716
717#### printf %b backslash escaping
718printf '[%s]\n' '\044' # escapes not evaluated
719printf '[%b]\n' '\044' # YES, escapes evaluated
720echo status=$?
721## STDOUT:
722[\044]
723[$]
724status=0
725## END
726
727#### printf %b with \c early return
728printf '[%b]\n' 'ab\ncd\cxy'
729echo $?
730## STDOUT:
731[ab
732cd0
733## END
734
735#### printf %c -- doesn't respect UTF-8! Bad.
736twomu=$'\u03bc\u03bc'
737printf '[%s]\n' "$twomu"
738printf '%c' "$twomu" | wc --bytes
739## STDOUT:
740[μμ]
7411
742## END
743## N-I dash STDOUT:
744[$\u03bc\u03bc]
7451
746## END
747## N-I ash STDOUT:
748[\u03bc\u03bc]
7491
750## END
751## N-I osh STDOUT:
752[μμ]
7530
754## END
755
756#### printf invalid format
757printf '%z' 42
758echo status=$?
759printf '%-z' 42
760echo status=$?
761## STDOUT:
762status=1
763status=1
764## END
765# osh emits parse errors
766## OK dash/osh STDOUT:
767status=2
768status=2
769## END
770
771#### printf %q
772x='a b'
773printf '[%q]\n' "$x"
774## STDOUT:
775['a b']
776## END
777## OK bash/zsh STDOUT:
778[a\ b]
779## END
780## N-I ash/dash stdout-json: "["
781## N-I ash status: 1
782## N-I dash status: 2
783
784#### printf %6q (width)
785# NOTE: coreutils /usr/bin/printf does NOT implement this %6q !!!
786x='a b'
787printf '[%6q]\n' "$x"
788printf '[%1q]\n' "$x"
789## STDOUT:
790[ 'a b']
791['a b']
792## END
793## OK bash/zsh STDOUT:
794[ a\ b]
795[a\ b]
796## END
797## N-I mksh/ash/dash stdout-json: "[["
798## N-I mksh/ash status: 1
799## N-I dash status: 2
800
801#### printf negative numbers
802printf '[%d] ' -42
803echo status=$?
804printf '[%i] ' -42
805echo status=$?
806
807# extra LEADING space too
808printf '[%d] ' ' -42'
809echo status=$?
810printf '[%i] ' ' -42'
811echo status=$?
812
813# extra TRAILING space too
814printf '[%d] ' ' -42 '
815echo status=$?
816printf '[%i] ' ' -42 '
817echo status=$?
818
819# extra TRAILING chars
820printf '[%d] ' ' -42z'
821echo status=$?
822printf '[%i] ' ' -42z'
823echo status=$?
824
825exit 0 # ok
826
827## STDOUT:
828[-42] status=0
829[-42] status=0
830[-42] status=0
831[-42] status=0
832[-42] status=1
833[-42] status=1
834[-42] status=1
835[-42] status=1
836## END
837# zsh is LESS STRICT
838## OK zsh STDOUT:
839[-42] status=0
840[-42] status=0
841[-42] status=0
842[-42] status=0
843[-42] status=0
844[-42] status=0
845[0] status=1
846[0] status=1
847## END
848
849# osh is like zsh but has a hard failure (TODO: could be an option?)
850## OK osh STDOUT:
851[-42] status=0
852[-42] status=0
853[-42] status=0
854[-42] status=0
855[-42] status=0
856[-42] status=0
857status=1
858status=1
859## END
860
861# ash is MORE STRICT
862## OK ash STDOUT:
863[-42] status=0
864[-42] status=0
865[-42] status=0
866[-42] status=0
867[0] status=1
868[0] status=1
869[0] status=1
870[0] status=1
871## END
872
873
874#### printf + and space flags
875# I didn't know these existed -- I only knew about - and 0 !
876printf '[%+d]\n' 42
877printf '[%+d]\n' -42
878printf '[% d]\n' 42
879printf '[% d]\n' -42
880## STDOUT:
881[+42]
882[-42]
883[ 42]
884[-42]
885## END
886## N-I osh stdout-json: ""
887## N-I osh status: 2
888
889#### printf # flag
890# I didn't know these existed -- I only knew about - and 0 !
891# Note: '#' flag for integers outputs a prefix ONLY WHEN the value is non-zero
892printf '[%#o][%#o]\n' 0 42
893printf '[%#x][%#x]\n' 0 42
894printf '[%#X][%#X]\n' 0 42
895echo ---
896# Note: '#' flag for %f, %g always outputs the decimal point.
897printf '[%.0f][%#.0f]\n' 3 3
898# Note: In addition, '#' flag for %g does not omit zeroes in fraction
899printf '[%g][%#g]\n' 3 3
900## STDOUT:
901[0][052]
902[0][0x2a]
903[0][0X2A]
904---
905[3][3.]
906[3][3.00000]
907## END
908## N-I osh STDOUT:
909---
910## END
911## N-I osh status: 2
912
913#### Runtime error for invalid integer
914x=3abc
915printf '%d\n' $x
916echo status=$?
917printf '%d\n' xyz
918echo status=$?
919## STDOUT:
9203
921status=1
9220
923status=1
924## END
925# zsh should exit 1 in both cases
926## BUG zsh STDOUT:
9270
928status=1
9290
930status=0
931## END
932# fails but also prints 0 instead of 3abc
933## BUG ash STDOUT:
9340
935status=1
9360
937status=1
938## END
939# osh doesn't print anything invalid
940## OK osh STDOUT:
941status=1
942status=1
943## END
944
945#### %(strftime format)T
946# The result depends on timezone
947export TZ=Asia/Tokyo
948printf '%(%Y-%m-%d)T\n' 1557978599
949export TZ=US/Eastern
950printf '%(%Y-%m-%d)T\n' 1557978599
951echo status=$?
952## STDOUT:
9532019-05-16
9542019-05-15
955status=0
956## END
957## N-I mksh/zsh/ash STDOUT:
958status=1
959## END
960## N-I dash STDOUT:
961status=2
962## END
963
964#### %(strftime format)T doesn't respect TZ if not exported
965
966# note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
967
968TZ=Portugal # NOT exported
969localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
970
971# TZ is respected
972export TZ=Portugal
973tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
974
975#echo $localtime
976#echo $tz
977
978if ! test "$localtime" = "$tz"; then
979 echo 'not equal'
980fi
981## STDOUT:
982not equal
983## END
984## N-I mksh/zsh/ash/dash stdout-json: ""
985
986#### %(strftime format)T TZ in environ but not in shell's memory
987
988# note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
989
990# TZ is respected
991export TZ=Portugal
992tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
993
994unset TZ # unset in the shell, but still in the environment
995
996localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
997
998if ! test "$localtime" = "$tz"; then
999 echo 'not equal'
1000fi
1001
1002## STDOUT:
1003not equal
1004## END
1005## N-I mksh/zsh/ash/dash stdout-json: ""
1006
1007#### %10.5(strftime format)T
1008# The result depends on timezone
1009export TZ=Asia/Tokyo
1010printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
1011export TZ=US/Eastern
1012printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
1013echo status=$?
1014## STDOUT:
1015[ 2019-]
1016[ 2019-]
1017status=0
1018## END
1019## N-I dash/mksh/zsh/ash STDOUT:
1020[[status=1
1021## END
1022## N-I dash STDOUT:
1023[[status=2
1024## END
1025
1026#### Regression for 'printf x y'
1027printf x y
1028printf '%s\n' z
1029## STDOUT:
1030xz
1031## END
1032
1033#### bash truncates long strftime string at 128
1034
1035case $SH in (ash|dash|mksh|zsh) exit ;; esac
1036
1037strftime-format() {
1038 local n=$1
1039
1040 # Prints increasingly long format strings:
1041 # %(%Y)T %(%Y)T %(%Y%Y)T ...
1042
1043 echo -n '%('
1044 for i in $(seq $n); do
1045 echo -n '%Y'
1046 done
1047 echo -n ')T'
1048}
1049
1050printf $(strftime-format 1) | wc --bytes
1051printf $(strftime-format 10) | wc --bytes
1052printf $(strftime-format 30) | wc --bytes
1053printf $(strftime-format 31) | wc --bytes
1054printf $(strftime-format 32) | wc --bytes
1055
1056case $SH in
1057 (*/_bin/cxx-dbg/*)
1058 # Ensure that oils-for-unix detects the truncation of a fixed buffer.
1059 # bash has a buffer of 128.
1060
1061 set +o errexit
1062 (
1063 printf $(strftime-format 1000)
1064 )
1065 status=$?
1066 if test $status -ne 1; then
1067 echo FAIL
1068 fi
1069 ;;
1070esac
1071
1072## STDOUT:
10734
107440
1075120
1076124
10770
1078## END
1079## OK osh STDOUT:
10804
108140
1082120
1083124
1084128
1085## END
1086
1087## N-I ash/dash/mksh/zsh STDOUT:
1088## END
1089
1090
1091#### printf with explicit NUL byte
1092case $SH in (dash|ash) return ;; esac
1093
1094printf $'x\U0z'
1095
1096printf $'\U0z'
1097
1098## stdout-json: "x"
1099## OK zsh stdout-repr: "x\0z\0z"
1100## N-I dash/ash stdout-json: ""