1 |
#!/usr/bin/env bash |
2 |
# |
3 |
# printf |
4 |
# bash-completion uses this odd printf -v construction. It seems to mostly use |
5 |
# %s and %q though. |
6 |
# |
7 |
# %s should just be |
8 |
# declare $var='val' |
9 |
# |
10 |
# NOTE: |
11 |
# /usr/bin/printf %q "'" seems wrong. |
12 |
# $ /usr/bin/printf %q "'" |
13 |
# ''\''' |
14 |
# |
15 |
# I suppose it is technically correct, but it looks very ugly. |
16 |
|
17 |
#### printf with no args |
18 |
printf |
19 |
## status: 2 |
20 |
## OK dash/mksh/zsh status: 1 |
21 |
## stdout-json: "" |
22 |
|
23 |
#### printf -v %s |
24 |
var=foo |
25 |
printf -v $var %s 'hello there' |
26 |
argv.py "$foo" |
27 |
## STDOUT: |
28 |
['hello there'] |
29 |
## END |
30 |
## N-I mksh/zsh/ash STDOUT: |
31 |
-v[''] |
32 |
## END |
33 |
## N-I dash STDOUT: |
34 |
[''] |
35 |
## END |
36 |
|
37 |
#### printf -v %q |
38 |
val='"quoted" with spaces and \' |
39 |
|
40 |
# quote 'val' and store it in foo |
41 |
printf -v foo %q "$val" |
42 |
# then round trip back to eval |
43 |
eval "bar=$foo" |
44 |
|
45 |
# debugging: |
46 |
#echo foo="$foo" |
47 |
#echo bar="$bar" |
48 |
#echo val="$val" |
49 |
|
50 |
test "$bar" = "$val" && echo OK |
51 |
## STDOUT: |
52 |
OK |
53 |
## END |
54 |
## N-I mksh/zsh/ash stdout-json: "-v" |
55 |
## N-I mksh/zsh/ash status: 1 |
56 |
## N-I dash stdout-json: "" |
57 |
## N-I dash status: 1 |
58 |
|
59 |
#### printf -v a[1] |
60 |
a=(a b c) |
61 |
printf -v 'a[1]' %s 'foo' |
62 |
echo status=$? |
63 |
argv.py "${a[@]}" |
64 |
## STDOUT: |
65 |
status=0 |
66 |
['a', 'foo', 'c'] |
67 |
## END |
68 |
## N-I mksh/zsh STDOUT: |
69 |
-vstatus=0 |
70 |
['a', 'b', 'c'] |
71 |
## END |
72 |
## N-I dash/ash stdout-json: "" |
73 |
## N-I dash/ash status: 2 |
74 |
## N-I osh STDOUT: |
75 |
status=2 |
76 |
['a', 'b', 'c'] |
77 |
## END |
78 |
|
79 |
#### dynamic declare instead of %s |
80 |
var=foo |
81 |
declare $var='hello there' |
82 |
argv.py "$foo" |
83 |
## STDOUT: |
84 |
['hello there'] |
85 |
## END |
86 |
## N-I dash/mksh/ash STDOUT: |
87 |
[''] |
88 |
## END |
89 |
|
90 |
#### dynamic declare instead of %q |
91 |
var=foo |
92 |
val='"quoted" with spaces and \' |
93 |
# I think this is bash 4.4 only. |
94 |
declare $var="${val@Q}" |
95 |
echo "$foo" |
96 |
## STDOUT: |
97 |
'"quoted" with spaces and \' |
98 |
## END |
99 |
## N-I dash/ash stdout-json: "" |
100 |
## N-I dash/ash status: 2 |
101 |
## N-I mksh stdout-json: "\n" |
102 |
## N-I zsh stdout-json: "" |
103 |
## N-I zsh status: 1 |
104 |
|
105 |
#### printf -v dynamic scope |
106 |
case $SH in *mksh|*zsh|*dash|*/ash) echo not implemented; exit ;; esac |
107 |
# OK so printf is like assigning to a var. |
108 |
# printf -v foo %q "$bar" is like |
109 |
# foo=${bar@Q} |
110 |
dollar='dollar' |
111 |
f() { |
112 |
local mylocal=foo |
113 |
printf -v dollar %q '$' # assign foo to a quoted dollar |
114 |
printf -v mylocal %q 'mylocal' |
115 |
echo dollar=$dollar |
116 |
echo mylocal=$mylocal |
117 |
} |
118 |
echo dollar=$dollar |
119 |
echo -- |
120 |
f |
121 |
echo -- |
122 |
echo dollar=$dollar |
123 |
echo mylocal=$mylocal |
124 |
## STDOUT: |
125 |
dollar=dollar |
126 |
-- |
127 |
dollar=\$ |
128 |
mylocal=mylocal |
129 |
-- |
130 |
dollar=\$ |
131 |
mylocal= |
132 |
## END |
133 |
## OK osh STDOUT: |
134 |
dollar=dollar |
135 |
-- |
136 |
dollar='$' |
137 |
mylocal='mylocal' |
138 |
-- |
139 |
dollar='$' |
140 |
mylocal= |
141 |
## END |
142 |
## N-I dash/ash/mksh/zsh STDOUT: |
143 |
not implemented |
144 |
## END |
145 |
|
146 |
#### printf with too few arguments |
147 |
printf -- '-%s-%s-%s-\n' 'a b' 'x y' |
148 |
## STDOUT: |
149 |
-a b-x y-- |
150 |
## END |
151 |
|
152 |
#### printf with too many arguments |
153 |
printf -- '-%s-%s-\n' a b c d e |
154 |
## STDOUT: |
155 |
-a-b- |
156 |
-c-d- |
157 |
-e-- |
158 |
## END |
159 |
|
160 |
#### printf width strings |
161 |
printf '[%5s]\n' abc |
162 |
printf '[%-5s]\n' abc |
163 |
## STDOUT: |
164 |
[ abc] |
165 |
[abc ] |
166 |
## END |
167 |
|
168 |
#### printf integer |
169 |
printf '%d\n' 42 |
170 |
printf '%i\n' 42 # synonym |
171 |
printf '[%5d]\n' 42 |
172 |
printf '[%-5d]\n' 42 |
173 |
printf '[%05d]\n' 42 |
174 |
#printf '[%-05d]\n' 42 # the leading 0 is meaningless |
175 |
#[42 ] |
176 |
## STDOUT: |
177 |
42 |
178 |
42 |
179 |
[ 42] |
180 |
[42 ] |
181 |
[00042] |
182 |
## END |
183 |
|
184 |
#### printf %6.4d -- precision means something different for integers !? |
185 |
printf '[%6.4d]\n' 42 |
186 |
## STDOUT: |
187 |
[ 0042] |
188 |
## END |
189 |
## N-I osh stdout-json: "" |
190 |
## N-I osh status: 2 |
191 |
|
192 |
#### printf %6.4s does both truncation and padding |
193 |
printf '[%6s]\n' foo |
194 |
printf '[%6.4s]\n' foo |
195 |
printf '[%-6.4s]\n' foo |
196 |
printf '[%6s]\n' spam-eggs |
197 |
printf '[%6.4s]\n' spam-eggs |
198 |
printf '[%-6.4s]\n' spam-eggs |
199 |
## STDOUT: |
200 |
[ foo] |
201 |
[ foo] |
202 |
[foo ] |
203 |
[spam-eggs] |
204 |
[ spam] |
205 |
[spam ] |
206 |
## END |
207 |
|
208 |
#### printf %6.0s and %0.0s |
209 |
printf '[%6.0s]\n' foo |
210 |
printf '[%0.0s]\n' foo |
211 |
## STDOUT: |
212 |
[ ] |
213 |
[] |
214 |
## END |
215 |
## N-I mksh stdout-json: "[ ]\n[" |
216 |
## N-I mksh status: 1 |
217 |
|
218 |
#### unsigned / octal / hex |
219 |
printf '[%u]\n' 42 |
220 |
printf '[%o]\n' 42 |
221 |
printf '[%x]\n' 42 |
222 |
printf '[%X]\n' 42 |
223 |
## STDOUT: |
224 |
[42] |
225 |
[52] |
226 |
[2a] |
227 |
[2A] |
228 |
## END |
229 |
|
230 |
#### negative numbers with unsigned / octal / hex |
231 |
printf '[%u]\n' -42 |
232 |
printf '[%o]\n' -42 |
233 |
printf '[%x]\n' -42 |
234 |
printf '[%X]\n' -42 |
235 |
## STDOUT: |
236 |
[18446744073709551574] |
237 |
[1777777777777777777726] |
238 |
[ffffffffffffffd6] |
239 |
[FFFFFFFFFFFFFFD6] |
240 |
## END |
241 |
|
242 |
# osh DISALLOWS this because the output depends on the machine architecture. |
243 |
## N-I osh stdout-json: "" |
244 |
## N-I osh status: 1 |
245 |
|
246 |
#### printf floating point (not required, but they all implement it) |
247 |
printf '[%f]\n' 3.14159 |
248 |
printf '[%.2f]\n' 3.14159 |
249 |
printf '[%8.2f]\n' 3.14159 |
250 |
printf '[%-8.2f]\n' 3.14159 |
251 |
printf '[%-f]\n' 3.14159 |
252 |
printf '[%-f]\n' 3.14 |
253 |
## STDOUT: |
254 |
[3.141590] |
255 |
[3.14] |
256 |
[ 3.14] |
257 |
[3.14 ] |
258 |
[3.141590] |
259 |
[3.140000] |
260 |
## END |
261 |
## N-I osh stdout-json: "" |
262 |
## N-I osh status: 2 |
263 |
|
264 |
#### printf floating point with - and 0 |
265 |
printf '[%8.4f]\n' 3.14 |
266 |
printf '[%08.4f]\n' 3.14 |
267 |
printf '[%8.04f]\n' 3.14 # meaning less 0 |
268 |
printf '[%08.04f]\n' 3.14 |
269 |
echo --- |
270 |
# these all boil down to the same thing. The -, 8, and 4 are respected, but |
271 |
# none of the 0 are. |
272 |
printf '[%-8.4f]\n' 3.14 |
273 |
printf '[%-08.4f]\n' 3.14 |
274 |
printf '[%-8.04f]\n' 3.14 |
275 |
printf '[%-08.04f]\n' 3.14 |
276 |
## STDOUT: |
277 |
[ 3.1400] |
278 |
[003.1400] |
279 |
[ 3.1400] |
280 |
[003.1400] |
281 |
--- |
282 |
[3.1400 ] |
283 |
[3.1400 ] |
284 |
[3.1400 ] |
285 |
[3.1400 ] |
286 |
## END |
287 |
## N-I osh STDOUT: |
288 |
--- |
289 |
## END |
290 |
## N-I osh status: 2 |
291 |
|
292 |
#### printf eE fF gG |
293 |
printf '[%e]\n' 3.14 |
294 |
printf '[%E]\n' 3.14 |
295 |
printf '[%f]\n' 3.14 |
296 |
# bash is the only one that implements %F? Is it a synonym? |
297 |
#printf '[%F]\n' 3.14 |
298 |
printf '[%g]\n' 3.14 |
299 |
printf '[%G]\n' 3.14 |
300 |
## STDOUT: |
301 |
[3.140000e+00] |
302 |
[3.140000E+00] |
303 |
[3.140000] |
304 |
[3.14] |
305 |
[3.14] |
306 |
## END |
307 |
## N-I osh stdout-json: "" |
308 |
## N-I osh status: 2 |
309 |
|
310 |
#### printf backslash escapes |
311 |
argv.py "$(printf 'a\tb')" |
312 |
argv.py "$(printf '\xE2\x98\xA0')" |
313 |
argv.py "$(printf '\044e')" |
314 |
argv.py "$(printf '\0377')" # out of range |
315 |
## STDOUT: |
316 |
['a\tb'] |
317 |
['\xe2\x98\xa0'] |
318 |
['$e'] |
319 |
['\x1f7'] |
320 |
## END |
321 |
## N-I dash STDOUT: |
322 |
['a\tb'] |
323 |
['\\xE2\\x98\\xA0'] |
324 |
['$e'] |
325 |
['\x1f7'] |
326 |
## END |
327 |
|
328 |
#### printf octal backslash escapes |
329 |
argv.py "$(printf '\0377')" |
330 |
argv.py "$(printf '\377')" |
331 |
## STDOUT: |
332 |
['\x1f7'] |
333 |
['\xff'] |
334 |
## END |
335 |
|
336 |
#### printf unicode backslash escapes |
337 |
argv.py "$(printf '\u2620')" |
338 |
argv.py "$(printf '\U0000065f')" |
339 |
## STDOUT: |
340 |
['\xe2\x98\xa0'] |
341 |
['\xd9\x9f'] |
342 |
## END |
343 |
## N-I dash/ash STDOUT: |
344 |
['\\u2620'] |
345 |
['\\U0000065f'] |
346 |
## END |
347 |
|
348 |
#### printf invalid backslash escape (is ignored) |
349 |
printf '[\Z]\n' |
350 |
## STDOUT: |
351 |
[\Z] |
352 |
## END |
353 |
|
354 |
#### printf % escapes |
355 |
printf '[%%]\n' |
356 |
## STDOUT: |
357 |
[%] |
358 |
## END |
359 |
|
360 |
#### printf %b backslash escaping |
361 |
printf '[%s]\n' '\044' # escapes not evaluated |
362 |
printf '[%b]\n' '\044' # YES, escapes evaluated |
363 |
echo status=$? |
364 |
## STDOUT: |
365 |
[\044] |
366 |
[$] |
367 |
status=0 |
368 |
## END |
369 |
## N-I osh STDOUT: |
370 |
[\044] |
371 |
status=2 |
372 |
## END |
373 |
|
374 |
#### printf %c -- doesn't respect UTF-8! Bad. |
375 |
twomu=$'\u03bc\u03bc' |
376 |
printf '[%s]\n' "$twomu" |
377 |
printf '%c' "$twomu" | wc --bytes |
378 |
## STDOUT: |
379 |
[μμ] |
380 |
1 |
381 |
## END |
382 |
## N-I dash STDOUT: |
383 |
[$\u03bc\u03bc] |
384 |
1 |
385 |
## END |
386 |
## N-I ash STDOUT: |
387 |
[\u03bc\u03bc] |
388 |
1 |
389 |
## END |
390 |
## N-I osh STDOUT: |
391 |
[μμ] |
392 |
0 |
393 |
## END |
394 |
|
395 |
#### printf invalid format |
396 |
printf '%z' 42 |
397 |
echo status=$? |
398 |
printf '%-z' 42 |
399 |
echo status=$? |
400 |
## STDOUT: |
401 |
status=1 |
402 |
status=1 |
403 |
## END |
404 |
# osh emits parse errors |
405 |
## OK osh STDOUT: |
406 |
status=2 |
407 |
status=2 |
408 |
## END |
409 |
## BUG ash STDOUT: |
410 |
status=0 |
411 |
status=0 |
412 |
## END |
413 |
|
414 |
#### printf %q |
415 |
x='a b' |
416 |
printf '[%q]\n' "$x" |
417 |
## STDOUT: |
418 |
['a b'] |
419 |
## END |
420 |
## OK bash/zsh STDOUT: |
421 |
[a\ b] |
422 |
## END |
423 |
## N-I ash/dash stdout-json: "[" |
424 |
## N-I ash/dash status: 1 |
425 |
|
426 |
#### printf %6q (width) |
427 |
# NOTE: coreutils /usr/bin/printf does NOT implement this %6q !!! |
428 |
x='a b' |
429 |
printf '[%6q]\n' "$x" |
430 |
## STDOUT: |
431 |
[ 'a b'] |
432 |
## END |
433 |
## OK bash/zsh STDOUT: |
434 |
[ a\ b] |
435 |
## END |
436 |
## N-I mksh/ash/dash stdout-json: "[" |
437 |
## N-I mksh/ash/dash status: 1 |
438 |
|
439 |
#### printf + and space flags |
440 |
# I didn't know these existed -- I only knew about - and 0 ! |
441 |
printf '[%+d]\n' 42 |
442 |
printf '[%+d]\n' -42 |
443 |
printf '[% d]\n' 42 |
444 |
printf '[% d]\n' -42 |
445 |
## STDOUT: |
446 |
[+42] |
447 |
[-42] |
448 |
[ 42] |
449 |
[-42] |
450 |
## END |
451 |
## N-I osh stdout-json: "" |
452 |
## N-I osh status: 2 |
453 |
|
454 |
#### printf # flag |
455 |
# I didn't know these existed -- I only knew about - and 0 ! |
456 |
printf '[%#o]\n' 42 |
457 |
printf '[%#x]\n' 42 |
458 |
printf '[%#X]\n' 42 |
459 |
echo --- |
460 |
printf '[%#f]\n' 3 |
461 |
## STDOUT: |
462 |
[052] |
463 |
[0x2a] |
464 |
[0X2A] |
465 |
--- |
466 |
[3.000000] |
467 |
## END |
468 |
## N-I osh STDOUT: |
469 |
--- |
470 |
## END |
471 |
## N-I osh status: 2 |
472 |
|
473 |
#### Runtime error for invalid integer |
474 |
x=3abc |
475 |
printf '%d\n' $x |
476 |
echo status=$? |
477 |
printf '%d\n' xyz |
478 |
echo status=$? |
479 |
## STDOUT: |
480 |
3 |
481 |
status=1 |
482 |
0 |
483 |
status=1 |
484 |
## END |
485 |
# zsh should exit 1 in both cases |
486 |
## BUG zsh STDOUT: |
487 |
0 |
488 |
status=1 |
489 |
0 |
490 |
status=0 |
491 |
## END |
492 |
# fails but also prints 0 instead of 3abc |
493 |
## BUG ash STDOUT: |
494 |
0 |
495 |
status=1 |
496 |
0 |
497 |
status=1 |
498 |
## END |
499 |
# osh doesn't print anything invalid |
500 |
## OK osh STDOUT: |
501 |
status=1 |
502 |
status=1 |
503 |
## END |
504 |
|
505 |
#### %(strftime format)T |
506 |
printf '%(%Y-%m-%d)T\n' 1557978599 |
507 |
echo status=$? |
508 |
## STDOUT: |
509 |
2019-05-15 |
510 |
status=0 |
511 |
## END |
512 |
## N-I dash/mksh/zsh/ash STDOUT: |
513 |
status=1 |
514 |
## END |
515 |
## N-I osh STDOUT: |
516 |
status=2 |
517 |
## END |