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
|
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 | echo
|
344 |
|
345 | printf '[%X]\n' \'a # if first character is a quote, use character code
|
346 | printf '[%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 |
|
360 | for 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
|
366 | done
|
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)
|
395 | printf '%d\n' ''
|
396 | ## OK osh stdout-json: ""
|
397 | ## OK osh status: 1
|
398 | ## OK ash status: 1
|
399 | ## STDOUT:
|
400 | 0
|
401 | ## END
|
402 |
|
403 | #### No char after ' => zero code point
|
404 |
|
405 | # most shells use 0 here
|
406 | printf '%d\n' \'
|
407 | printf '%d\n' \"
|
408 |
|
409 | ## OK mksh status: 1
|
410 | ## STDOUT:
|
411 | 0
|
412 | 0
|
413 | ## END
|
414 |
|
415 | #### Unicode char with '
|
416 | case $SH in mksh) echo 'weird bug'; exit ;; esac
|
417 |
|
418 | # the mu character is U+03BC
|
419 |
|
420 | printf '%x\n' \'μ
|
421 | printf '%u\n' \'μ
|
422 | printf '%o\n' \'μ
|
423 | echo
|
424 |
|
425 | u3=三
|
426 | # u4=😘
|
427 |
|
428 | printf '%x\n' \'$u3
|
429 | printf '%u\n' \'$u3
|
430 | printf '%o\n' \'$u3
|
431 | echo
|
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:
|
474 | 3bc
|
475 | 956
|
476 | 1674
|
477 |
|
478 | 4e09
|
479 | 19977
|
480 | 47011
|
481 |
|
482 | ## END
|
483 | ## BUG dash/ash STDOUT:
|
484 | ce
|
485 | 206
|
486 | 316
|
487 |
|
488 | e4
|
489 | 228
|
490 | 344
|
491 |
|
492 | ## END
|
493 |
|
494 | ## BUG mksh STDOUT:
|
495 | weird bug
|
496 | ## END
|
497 |
|
498 | #### Invalid UTF-8
|
499 |
|
500 | echo bytes1
|
501 | not_utf8=$(python2 -c 'print("\xce\xce")')
|
502 |
|
503 | printf '%x\n' \'$not_utf8
|
504 | printf '%u\n' \'$not_utf8
|
505 | printf '%o\n' \'$not_utf8
|
506 | echo
|
507 |
|
508 | echo bytes2
|
509 | not_utf8=$(python2 -c 'print("\xbc\xbc")')
|
510 | printf '%x\n' \'$not_utf8
|
511 | printf '%u\n' \'$not_utf8
|
512 | printf '%o\n' \'$not_utf8
|
513 | echo
|
514 |
|
515 | # Copied from data_lang/utf8_test.cc
|
516 |
|
517 | echo overlong2
|
518 | overlong2=$(python2 -c 'print("\xC1\x81")')
|
519 | printf '%x\n' \'$overlong2
|
520 | printf '%u\n' \'$overlong2
|
521 | printf '%o\n' \'$overlong2
|
522 | echo
|
523 |
|
524 | echo overlong3
|
525 | overlong3=$(python2 -c 'print("\xE0\x81\x81")')
|
526 | printf '%x\n' \'$overlong3
|
527 | printf '%u\n' \'$overlong3
|
528 | printf '%o\n' \'$overlong3
|
529 | echo
|
530 |
|
531 | ## STDOUT:
|
532 | bytes1
|
533 | ce
|
534 | 206
|
535 | 316
|
536 |
|
537 | bytes2
|
538 | bc
|
539 | 188
|
540 | 274
|
541 |
|
542 | overlong2
|
543 | c1
|
544 | 193
|
545 | 301
|
546 |
|
547 | overlong3
|
548 | e0
|
549 | 224
|
550 | 340
|
551 |
|
552 | ## END
|
553 |
|
554 |
|
555 | #### Too large
|
556 | case $SH in mksh) echo 'weird bug'; exit ;; esac
|
557 |
|
558 | echo too large
|
559 | too_large=$(python2 -c 'print("\xF4\x91\x84\x91")')
|
560 | printf '%x\n' \'$too_large
|
561 | printf '%u\n' \'$too_large
|
562 | printf '%o\n' \'$too_large
|
563 | echo
|
564 |
|
565 | ## STDOUT:
|
566 | too large
|
567 | 111111
|
568 | 1118481
|
569 | 4210421
|
570 |
|
571 | ## END
|
572 |
|
573 | ## BUG dash/ash STDOUT:
|
574 | too large
|
575 | f4
|
576 | 244
|
577 | 364
|
578 |
|
579 | ## END
|
580 |
|
581 | ## BUG mksh STDOUT:
|
582 | weird bug
|
583 | ## END
|
584 |
|
585 | # osh rejects code points that are too large for a DIFFERENT reason
|
586 |
|
587 | ## OK osh STDOUT:
|
588 | too large
|
589 | f4
|
590 | 244
|
591 | 364
|
592 |
|
593 | ## END
|
594 |
|
595 |
|
596 | #### negative numbers with unsigned / octal / hex
|
597 | printf '[%u]\n' -42
|
598 | echo status=$?
|
599 |
|
600 | printf '[%o]\n' -42
|
601 | echo status=$?
|
602 |
|
603 | printf '[%x]\n' -42
|
604 | echo status=$?
|
605 |
|
606 | printf '[%X]\n' -42
|
607 | echo status=$?
|
608 |
|
609 | ## STDOUT:
|
610 | [18446744073709551574]
|
611 | status=0
|
612 | [1777777777777777777726]
|
613 | status=0
|
614 | [ffffffffffffffd6]
|
615 | status=0
|
616 | [FFFFFFFFFFFFFFD6]
|
617 | status=0
|
618 | ## END
|
619 |
|
620 | # osh DISALLOWS this because the output depends on the machine architecture.
|
621 | ## N-I osh STDOUT:
|
622 | status=1
|
623 | status=1
|
624 | status=1
|
625 | status=1
|
626 | ## END
|
627 |
|
628 | #### printf floating point (not required, but they all implement it)
|
629 | printf '[%f]\n' 3.14159
|
630 | printf '[%.2f]\n' 3.14159
|
631 | printf '[%8.2f]\n' 3.14159
|
632 | printf '[%-8.2f]\n' 3.14159
|
633 | printf '[%-f]\n' 3.14159
|
634 | printf '[%-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
|
647 | printf '[%8.4f]\n' 3.14
|
648 | printf '[%08.4f]\n' 3.14
|
649 | printf '[%8.04f]\n' 3.14 # meaning less 0
|
650 | printf '[%08.04f]\n' 3.14
|
651 | echo ---
|
652 | # these all boil down to the same thing. The -, 8, and 4 are respected, but
|
653 | # none of the 0 are.
|
654 | printf '[%-8.4f]\n' 3.14
|
655 | printf '[%-08.4f]\n' 3.14
|
656 | printf '[%-8.04f]\n' 3.14
|
657 | printf '[%-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
|
675 | printf '[%e]\n' 3.14
|
676 | printf '[%E]\n' 3.14
|
677 | printf '[%f]\n' 3.14
|
678 | # bash is the only one that implements %F? Is it a synonym?
|
679 | #printf '[%F]\n' 3.14
|
680 | printf '[%g]\n' 3.14
|
681 | printf '[%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
|
693 | argv.py "$(printf 'a\tb')"
|
694 | argv.py "$(printf '\xE2\x98\xA0')"
|
695 | argv.py "$(printf '\044e')"
|
696 | argv.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
|
711 | argv.py "$(printf '\0377')"
|
712 | argv.py "$(printf '\377')"
|
713 | ## STDOUT:
|
714 | ['\x1f7']
|
715 | ['\xff']
|
716 | ## END
|
717 |
|
718 | #### printf unicode backslash escapes
|
719 | argv.py "$(printf '\u2620')"
|
720 | argv.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)
|
731 | printf '[\Z]\n'
|
732 | ## STDOUT:
|
733 | [\Z]
|
734 | ## END
|
735 |
|
736 | #### printf % escapes
|
737 | printf '[%%]\n'
|
738 | ## STDOUT:
|
739 | [%]
|
740 | ## END
|
741 |
|
742 | #### printf %b backslash escaping
|
743 | printf '[%s]\n' '\044' # escapes not evaluated
|
744 | printf '[%b]\n' '\044' # YES, escapes evaluated
|
745 | echo status=$?
|
746 | ## STDOUT:
|
747 | [\044]
|
748 | [$]
|
749 | status=0
|
750 | ## END
|
751 |
|
752 | #### printf %b with \c early return
|
753 | printf '[%b]\n' 'ab\ncd\cxy'
|
754 | echo $?
|
755 | ## STDOUT:
|
756 | [ab
|
757 | cd0
|
758 | ## END
|
759 |
|
760 | #### printf %c -- doesn't respect UTF-8! Bad.
|
761 | twomu=$'\u03bc\u03bc'
|
762 | printf '[%s]\n' "$twomu"
|
763 | printf '%c' "$twomu" | wc --bytes
|
764 | ## STDOUT:
|
765 | [μμ]
|
766 | 1
|
767 | ## END
|
768 | ## N-I dash STDOUT:
|
769 | [$\u03bc\u03bc]
|
770 | 1
|
771 | ## END
|
772 | ## N-I ash STDOUT:
|
773 | [\u03bc\u03bc]
|
774 | 1
|
775 | ## END
|
776 | ## N-I osh STDOUT:
|
777 | [μμ]
|
778 | 0
|
779 | ## END
|
780 |
|
781 | #### printf invalid format
|
782 | printf '%z' 42
|
783 | echo status=$?
|
784 | printf '%-z' 42
|
785 | echo status=$?
|
786 | ## STDOUT:
|
787 | status=1
|
788 | status=1
|
789 | ## END
|
790 | # osh emits parse errors
|
791 | ## OK dash/osh STDOUT:
|
792 | status=2
|
793 | status=2
|
794 | ## END
|
795 |
|
796 | #### printf %q
|
797 | x='a b'
|
798 | printf '[%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 !!!
|
811 | x='a b'
|
812 | printf '[%6q]\n' "$x"
|
813 | printf '[%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
|
827 | printf '[%d] ' -42
|
828 | echo status=$?
|
829 | printf '[%i] ' -42
|
830 | echo status=$?
|
831 |
|
832 | # extra LEADING space too
|
833 | printf '[%d] ' ' -42'
|
834 | echo status=$?
|
835 | printf '[%i] ' ' -42'
|
836 | echo status=$?
|
837 |
|
838 | # extra TRAILING space too
|
839 | printf '[%d] ' ' -42 '
|
840 | echo status=$?
|
841 | printf '[%i] ' ' -42 '
|
842 | echo status=$?
|
843 |
|
844 | # extra TRAILING chars
|
845 | printf '[%d] ' ' -42z'
|
846 | echo status=$?
|
847 | printf '[%i] ' ' -42z'
|
848 | echo status=$?
|
849 |
|
850 | exit 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
|
882 | status=1
|
883 | status=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 !
|
901 | printf '[%+d]\n' 42
|
902 | printf '[%+d]\n' -42
|
903 | printf '[% d]\n' 42
|
904 | printf '[% 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
|
917 | printf '[%#o][%#o]\n' 0 42
|
918 | printf '[%#x][%#x]\n' 0 42
|
919 | printf '[%#X][%#X]\n' 0 42
|
920 | echo ---
|
921 | # Note: '#' flag for %f, %g always outputs the decimal point.
|
922 | printf '[%.0f][%#.0f]\n' 3 3
|
923 | # Note: In addition, '#' flag for %g does not omit zeroes in fraction
|
924 | printf '[%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
|
939 | x=3abc
|
940 | printf '%d\n' $x
|
941 | echo status=$?
|
942 | printf '%d\n' xyz
|
943 | echo status=$?
|
944 | ## STDOUT:
|
945 | 3
|
946 | status=1
|
947 | 0
|
948 | status=1
|
949 | ## END
|
950 | # zsh should exit 1 in both cases
|
951 | ## BUG zsh STDOUT:
|
952 | 0
|
953 | status=1
|
954 | 0
|
955 | status=0
|
956 | ## END
|
957 | # fails but also prints 0 instead of 3abc
|
958 | ## BUG ash STDOUT:
|
959 | 0
|
960 | status=1
|
961 | 0
|
962 | status=1
|
963 | ## END
|
964 | # osh doesn't print anything invalid
|
965 | ## OK osh STDOUT:
|
966 | status=1
|
967 | status=1
|
968 | ## END
|
969 |
|
970 | #### %(strftime format)T
|
971 | # The result depends on timezone
|
972 | export TZ=Asia/Tokyo
|
973 | printf '%(%Y-%m-%d)T\n' 1557978599
|
974 | export TZ=US/Eastern
|
975 | printf '%(%Y-%m-%d)T\n' 1557978599
|
976 | echo status=$?
|
977 | ## STDOUT:
|
978 | 2019-05-16
|
979 | 2019-05-15
|
980 | status=0
|
981 | ## END
|
982 | ## N-I mksh/zsh/ash STDOUT:
|
983 | status=1
|
984 | ## END
|
985 | ## N-I dash STDOUT:
|
986 | status=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 |
|
993 | TZ=Portugal # NOT exported
|
994 | localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
995 |
|
996 | # TZ is respected
|
997 | export TZ=Portugal
|
998 | tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
999 |
|
1000 | #echo $localtime
|
1001 | #echo $tz
|
1002 |
|
1003 | if ! test "$localtime" = "$tz"; then
|
1004 | echo 'not equal'
|
1005 | fi
|
1006 | ## STDOUT:
|
1007 | not 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
|
1016 | export TZ=Portugal
|
1017 | tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
1018 |
|
1019 | unset TZ # unset in the shell, but still in the environment
|
1020 |
|
1021 | localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
1022 |
|
1023 | if ! test "$localtime" = "$tz"; then
|
1024 | echo 'not equal'
|
1025 | fi
|
1026 |
|
1027 | ## STDOUT:
|
1028 | not 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
|
1034 | export TZ=Asia/Tokyo
|
1035 | printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
|
1036 | export TZ=US/Eastern
|
1037 | printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
|
1038 | echo status=$?
|
1039 | ## STDOUT:
|
1040 | [ 2019-]
|
1041 | [ 2019-]
|
1042 | status=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'
|
1052 | printf x y
|
1053 | printf '%s\n' z
|
1054 | ## STDOUT:
|
1055 | xz
|
1056 | ## END
|
1057 |
|
1058 | #### bash truncates long strftime string at 128
|
1059 |
|
1060 | case $SH in (ash|dash|mksh|zsh) exit ;; esac
|
1061 |
|
1062 | strftime-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 |
|
1075 | printf $(strftime-format 1) | wc --bytes
|
1076 | printf $(strftime-format 10) | wc --bytes
|
1077 | printf $(strftime-format 30) | wc --bytes
|
1078 | printf $(strftime-format 31) | wc --bytes
|
1079 | printf $(strftime-format 32) | wc --bytes
|
1080 |
|
1081 | case $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 | ;;
|
1095 | esac
|
1096 |
|
1097 | ## STDOUT:
|
1098 | 4
|
1099 | 40
|
1100 | 120
|
1101 | 124
|
1102 | 0
|
1103 | ## END
|
1104 | ## OK osh STDOUT:
|
1105 | 4
|
1106 | 40
|
1107 | 120
|
1108 | 124
|
1109 | 128
|
1110 | ## END
|
1111 |
|
1112 | ## N-I ash/dash/mksh/zsh STDOUT:
|
1113 | ## END
|
1114 |
|
1115 |
|
1116 | #### printf with explicit NUL byte
|
1117 | case $SH in (dash|ash) return ;; esac
|
1118 |
|
1119 | printf $'x\U0z'
|
1120 |
|
1121 | printf $'\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 |
|
1131 | for 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
|
1141 | done
|
1142 |
|
1143 | ## STDOUT:
|
1144 | status=1
|
1145 | status=1
|
1146 |
|
1147 | status=1
|
1148 | status=1
|
1149 |
|
1150 | ## END
|
1151 |
|
1152 | ## OK bash status: 0
|
1153 | ## OK bash STDOUT:
|
1154 | 18446744073709551615
|
1155 | status=0
|
1156 | 18446744073709551615
|
1157 | status=0
|
1158 |
|
1159 | 9223372036854775807
|
1160 | status=0
|
1161 | 9223372036854775807
|
1162 | status=0
|
1163 |
|
1164 | ## END
|
1165 |
|
1166 | ## OK dash/mksh status: 0
|
1167 | ## OK dash/mksh STDOUT:
|
1168 | 18446744073709551615
|
1169 | status=0
|
1170 | 18446744073709551615
|
1171 | status=1
|
1172 |
|
1173 | 9223372036854775807
|
1174 | status=1
|
1175 | 9223372036854775807
|
1176 | status=1
|
1177 |
|
1178 | ## END
|
1179 |
|
1180 | ## BUG ash status: 0
|
1181 | ## BUG ash STDOUT:
|
1182 | 18446744073709551615
|
1183 | status=0
|
1184 | 0
|
1185 | status=1
|
1186 |
|
1187 | 0
|
1188 | status=1
|
1189 | 0
|
1190 | status=1
|
1191 |
|
1192 | ## END
|
1193 |
|
1194 | ## BUG zsh status: 0
|
1195 | ## BUG zsh STDOUT:
|
1196 | 1844674407370955161
|
1197 | status=0
|
1198 | 1844674407370955161
|
1199 | status=0
|
1200 |
|
1201 | 1844674407370955161
|
1202 | status=0
|
1203 | 1844674407370955161
|
1204 | status=0
|
1205 |
|
1206 | ## END
|
1207 |
|
1208 | #### printf negative integer overflow
|
1209 |
|
1210 | # %i seems like a synonym for %d
|
1211 |
|
1212 | for fmt in '%u\n' '%d\n'; do
|
1213 |
|
1214 | printf "$fmt" '-18446744073709551615'
|
1215 | echo status=$?
|
1216 | printf "$fmt" '-18446744073709551616'
|
1217 | echo status=$?
|
1218 | echo
|
1219 | done
|
1220 |
|
1221 | ## STDOUT:
|
1222 | status=1
|
1223 | status=1
|
1224 |
|
1225 | status=1
|
1226 | status=1
|
1227 |
|
1228 | ## END
|
1229 |
|
1230 | ## OK bash status: 0
|
1231 | ## OK bash STDOUT:
|
1232 | 1
|
1233 | status=0
|
1234 | 18446744073709551615
|
1235 | status=0
|
1236 |
|
1237 | -9223372036854775808
|
1238 | status=0
|
1239 | -9223372036854775808
|
1240 | status=0
|
1241 |
|
1242 | ## END
|
1243 |
|
1244 | ## OK dash/mksh status: 0
|
1245 | ## OK dash/mksh STDOUT:
|
1246 | 1
|
1247 | status=0
|
1248 | 18446744073709551615
|
1249 | status=1
|
1250 |
|
1251 | -9223372036854775808
|
1252 | status=1
|
1253 | -9223372036854775808
|
1254 | status=1
|
1255 |
|
1256 | ## END
|
1257 |
|
1258 | ## BUG zsh status: 0
|
1259 | ## BUG zsh STDOUT:
|
1260 | 16602069666338596455
|
1261 | status=0
|
1262 | 16602069666338596455
|
1263 | status=0
|
1264 |
|
1265 | -1844674407370955161
|
1266 | status=0
|
1267 | -1844674407370955161
|
1268 | status=0
|
1269 |
|
1270 | ## END
|
1271 |
|
1272 | ## BUG ash status: 0
|
1273 | ## BUG ash STDOUT:
|
1274 | 0
|
1275 | status=1
|
1276 | 0
|
1277 | status=1
|
1278 |
|
1279 | 0
|
1280 | status=1
|
1281 | 0
|
1282 | status=1
|
1283 |
|
1284 | ## END
|