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 | #env
|
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/mksh STDOUT:
|
484 | ce
|
485 | 206
|
486 | 316
|
487 |
|
488 | e4
|
489 | 228
|
490 | 344
|
491 |
|
492 | ## END
|
493 |
|
494 | #### Invalid UTF-8
|
495 |
|
496 | echo bytes1
|
497 | not_utf8=$(python2 -c 'print("\xce\xce")')
|
498 |
|
499 | printf '%x\n' \'$not_utf8
|
500 | printf '%u\n' \'$not_utf8
|
501 | printf '%o\n' \'$not_utf8
|
502 | echo
|
503 |
|
504 | echo bytes2
|
505 | not_utf8=$(python2 -c 'print("\xbc\xbc")')
|
506 | printf '%x\n' \'$not_utf8
|
507 | printf '%u\n' \'$not_utf8
|
508 | printf '%o\n' \'$not_utf8
|
509 | echo
|
510 |
|
511 | # Copied from data_lang/utf8_test.cc
|
512 |
|
513 | echo overlong2
|
514 | overlong2=$(python2 -c 'print("\xC1\x81")')
|
515 | printf '%x\n' \'$overlong2
|
516 | printf '%u\n' \'$overlong2
|
517 | printf '%o\n' \'$overlong2
|
518 | echo
|
519 |
|
520 | echo overlong3
|
521 | overlong3=$(python2 -c 'print("\xE0\x81\x81")')
|
522 | printf '%x\n' \'$overlong3
|
523 | printf '%u\n' \'$overlong3
|
524 | printf '%o\n' \'$overlong3
|
525 | echo
|
526 |
|
527 | ## STDOUT:
|
528 | bytes1
|
529 | ce
|
530 | 206
|
531 | 316
|
532 |
|
533 | bytes2
|
534 | bc
|
535 | 188
|
536 | 274
|
537 |
|
538 | overlong2
|
539 | c1
|
540 | 193
|
541 | 301
|
542 |
|
543 | overlong3
|
544 | e0
|
545 | 224
|
546 | 340
|
547 |
|
548 | ## END
|
549 |
|
550 |
|
551 | #### Too large
|
552 |
|
553 | echo too large
|
554 | too_large=$(python2 -c 'print("\xF4\x91\x84\x91")')
|
555 | printf '%x\n' \'$too_large
|
556 | printf '%u\n' \'$too_large
|
557 | printf '%o\n' \'$too_large
|
558 | echo
|
559 |
|
560 | ## STDOUT:
|
561 | too large
|
562 | 111111
|
563 | 1118481
|
564 | 4210421
|
565 |
|
566 | ## END
|
567 |
|
568 | ## BUG dash/ash/mksh STDOUT:
|
569 | too large
|
570 | f4
|
571 | 244
|
572 | 364
|
573 |
|
574 | ## END
|
575 |
|
576 | # osh rejects code points that are too large for a DIFFERENT reason
|
577 |
|
578 | ## OK osh STDOUT:
|
579 | too large
|
580 | f4
|
581 | 244
|
582 | 364
|
583 |
|
584 | ## END
|
585 |
|
586 |
|
587 | #### negative numbers with unsigned / octal / hex
|
588 | printf '[%u]\n' -42
|
589 | printf '[%o]\n' -42
|
590 | printf '[%x]\n' -42
|
591 | printf '[%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)
|
604 | printf '[%f]\n' 3.14159
|
605 | printf '[%.2f]\n' 3.14159
|
606 | printf '[%8.2f]\n' 3.14159
|
607 | printf '[%-8.2f]\n' 3.14159
|
608 | printf '[%-f]\n' 3.14159
|
609 | printf '[%-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
|
622 | printf '[%8.4f]\n' 3.14
|
623 | printf '[%08.4f]\n' 3.14
|
624 | printf '[%8.04f]\n' 3.14 # meaning less 0
|
625 | printf '[%08.04f]\n' 3.14
|
626 | echo ---
|
627 | # these all boil down to the same thing. The -, 8, and 4 are respected, but
|
628 | # none of the 0 are.
|
629 | printf '[%-8.4f]\n' 3.14
|
630 | printf '[%-08.4f]\n' 3.14
|
631 | printf '[%-8.04f]\n' 3.14
|
632 | printf '[%-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
|
650 | printf '[%e]\n' 3.14
|
651 | printf '[%E]\n' 3.14
|
652 | printf '[%f]\n' 3.14
|
653 | # bash is the only one that implements %F? Is it a synonym?
|
654 | #printf '[%F]\n' 3.14
|
655 | printf '[%g]\n' 3.14
|
656 | printf '[%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
|
668 | argv.py "$(printf 'a\tb')"
|
669 | argv.py "$(printf '\xE2\x98\xA0')"
|
670 | argv.py "$(printf '\044e')"
|
671 | argv.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
|
686 | argv.py "$(printf '\0377')"
|
687 | argv.py "$(printf '\377')"
|
688 | ## STDOUT:
|
689 | ['\x1f7']
|
690 | ['\xff']
|
691 | ## END
|
692 |
|
693 | #### printf unicode backslash escapes
|
694 | argv.py "$(printf '\u2620')"
|
695 | argv.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)
|
706 | printf '[\Z]\n'
|
707 | ## STDOUT:
|
708 | [\Z]
|
709 | ## END
|
710 |
|
711 | #### printf % escapes
|
712 | printf '[%%]\n'
|
713 | ## STDOUT:
|
714 | [%]
|
715 | ## END
|
716 |
|
717 | #### printf %b backslash escaping
|
718 | printf '[%s]\n' '\044' # escapes not evaluated
|
719 | printf '[%b]\n' '\044' # YES, escapes evaluated
|
720 | echo status=$?
|
721 | ## STDOUT:
|
722 | [\044]
|
723 | [$]
|
724 | status=0
|
725 | ## END
|
726 |
|
727 | #### printf %b with \c early return
|
728 | printf '[%b]\n' 'ab\ncd\cxy'
|
729 | echo $?
|
730 | ## STDOUT:
|
731 | [ab
|
732 | cd0
|
733 | ## END
|
734 |
|
735 | #### printf %c -- doesn't respect UTF-8! Bad.
|
736 | twomu=$'\u03bc\u03bc'
|
737 | printf '[%s]\n' "$twomu"
|
738 | printf '%c' "$twomu" | wc --bytes
|
739 | ## STDOUT:
|
740 | [μμ]
|
741 | 1
|
742 | ## END
|
743 | ## N-I dash STDOUT:
|
744 | [$\u03bc\u03bc]
|
745 | 1
|
746 | ## END
|
747 | ## N-I ash STDOUT:
|
748 | [\u03bc\u03bc]
|
749 | 1
|
750 | ## END
|
751 | ## N-I osh STDOUT:
|
752 | [μμ]
|
753 | 0
|
754 | ## END
|
755 |
|
756 | #### printf invalid format
|
757 | printf '%z' 42
|
758 | echo status=$?
|
759 | printf '%-z' 42
|
760 | echo status=$?
|
761 | ## STDOUT:
|
762 | status=1
|
763 | status=1
|
764 | ## END
|
765 | # osh emits parse errors
|
766 | ## OK dash/osh STDOUT:
|
767 | status=2
|
768 | status=2
|
769 | ## END
|
770 |
|
771 | #### printf %q
|
772 | x='a b'
|
773 | printf '[%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 !!!
|
786 | x='a b'
|
787 | printf '[%6q]\n' "$x"
|
788 | printf '[%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
|
802 | printf '[%d] ' -42
|
803 | echo status=$?
|
804 | printf '[%i] ' -42
|
805 | echo status=$?
|
806 |
|
807 | # extra LEADING space too
|
808 | printf '[%d] ' ' -42'
|
809 | echo status=$?
|
810 | printf '[%i] ' ' -42'
|
811 | echo status=$?
|
812 |
|
813 | # extra TRAILING space too
|
814 | printf '[%d] ' ' -42 '
|
815 | echo status=$?
|
816 | printf '[%i] ' ' -42 '
|
817 | echo status=$?
|
818 |
|
819 | # extra TRAILING chars
|
820 | printf '[%d] ' ' -42z'
|
821 | echo status=$?
|
822 | printf '[%i] ' ' -42z'
|
823 | echo status=$?
|
824 |
|
825 | exit 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
|
857 | status=1
|
858 | status=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 !
|
876 | printf '[%+d]\n' 42
|
877 | printf '[%+d]\n' -42
|
878 | printf '[% d]\n' 42
|
879 | printf '[% 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
|
892 | printf '[%#o][%#o]\n' 0 42
|
893 | printf '[%#x][%#x]\n' 0 42
|
894 | printf '[%#X][%#X]\n' 0 42
|
895 | echo ---
|
896 | # Note: '#' flag for %f, %g always outputs the decimal point.
|
897 | printf '[%.0f][%#.0f]\n' 3 3
|
898 | # Note: In addition, '#' flag for %g does not omit zeroes in fraction
|
899 | printf '[%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
|
914 | x=3abc
|
915 | printf '%d\n' $x
|
916 | echo status=$?
|
917 | printf '%d\n' xyz
|
918 | echo status=$?
|
919 | ## STDOUT:
|
920 | 3
|
921 | status=1
|
922 | 0
|
923 | status=1
|
924 | ## END
|
925 | # zsh should exit 1 in both cases
|
926 | ## BUG zsh STDOUT:
|
927 | 0
|
928 | status=1
|
929 | 0
|
930 | status=0
|
931 | ## END
|
932 | # fails but also prints 0 instead of 3abc
|
933 | ## BUG ash STDOUT:
|
934 | 0
|
935 | status=1
|
936 | 0
|
937 | status=1
|
938 | ## END
|
939 | # osh doesn't print anything invalid
|
940 | ## OK osh STDOUT:
|
941 | status=1
|
942 | status=1
|
943 | ## END
|
944 |
|
945 | #### %(strftime format)T
|
946 | # The result depends on timezone
|
947 | export TZ=Asia/Tokyo
|
948 | printf '%(%Y-%m-%d)T\n' 1557978599
|
949 | export TZ=US/Eastern
|
950 | printf '%(%Y-%m-%d)T\n' 1557978599
|
951 | echo status=$?
|
952 | ## STDOUT:
|
953 | 2019-05-16
|
954 | 2019-05-15
|
955 | status=0
|
956 | ## END
|
957 | ## N-I mksh/zsh/ash STDOUT:
|
958 | status=1
|
959 | ## END
|
960 | ## N-I dash STDOUT:
|
961 | status=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 |
|
968 | TZ=Portugal # NOT exported
|
969 | localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
970 |
|
971 | # TZ is respected
|
972 | export TZ=Portugal
|
973 | tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
974 |
|
975 | #echo $localtime
|
976 | #echo $tz
|
977 |
|
978 | if ! test "$localtime" = "$tz"; then
|
979 | echo 'not equal'
|
980 | fi
|
981 | ## STDOUT:
|
982 | not 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
|
991 | export TZ=Portugal
|
992 | tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
993 |
|
994 | unset TZ # unset in the shell, but still in the environment
|
995 |
|
996 | localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
|
997 |
|
998 | if ! test "$localtime" = "$tz"; then
|
999 | echo 'not equal'
|
1000 | fi
|
1001 |
|
1002 | ## STDOUT:
|
1003 | not 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
|
1009 | export TZ=Asia/Tokyo
|
1010 | printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
|
1011 | export TZ=US/Eastern
|
1012 | printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
|
1013 | echo status=$?
|
1014 | ## STDOUT:
|
1015 | [ 2019-]
|
1016 | [ 2019-]
|
1017 | status=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'
|
1027 | printf x y
|
1028 | printf '%s\n' z
|
1029 | ## STDOUT:
|
1030 | xz
|
1031 | ## END
|
1032 |
|
1033 | #### bash truncates long strftime string at 128
|
1034 |
|
1035 | case $SH in (ash|dash|mksh|zsh) exit ;; esac
|
1036 |
|
1037 | strftime-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 |
|
1050 | printf $(strftime-format 1) | wc --bytes
|
1051 | printf $(strftime-format 10) | wc --bytes
|
1052 | printf $(strftime-format 30) | wc --bytes
|
1053 | printf $(strftime-format 31) | wc --bytes
|
1054 | printf $(strftime-format 32) | wc --bytes
|
1055 |
|
1056 | case $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 | ;;
|
1070 | esac
|
1071 |
|
1072 | ## STDOUT:
|
1073 | 4
|
1074 | 40
|
1075 | 120
|
1076 | 124
|
1077 | 0
|
1078 | ## END
|
1079 | ## OK osh STDOUT:
|
1080 | 4
|
1081 | 40
|
1082 | 120
|
1083 | 124
|
1084 | 128
|
1085 | ## END
|
1086 |
|
1087 | ## N-I ash/dash/mksh/zsh STDOUT:
|
1088 | ## END
|
1089 |
|
1090 |
|
1091 | #### printf with explicit NUL byte
|
1092 | case $SH in (dash|ash) return ;; esac
|
1093 |
|
1094 | printf $'x\U0z'
|
1095 |
|
1096 | printf $'\U0z'
|
1097 |
|
1098 | ## stdout-json: "x"
|
1099 | ## OK zsh stdout-repr: "x\0z\0z"
|
1100 | ## N-I dash/ash stdout-json: ""
|