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