name: "Builtins: printf" cases: # Basic functionality tests - name: "One-variable printf" stdin: | printf "%s" "0" - name: "Basic printf" stdin: | printf "%s, %s" "Hello" "world" - name: "printf -v" stdin: | printf -v myvar "%s, %s" "Hello" "world" echo "myvar: '${myvar}'" - name: "printf -v with array index" stdin: | declare -a myarray=() printf -v 'myarray[5]' "%s, %s" "Hello" "world" declare | grep myarray - name: "printf with -v as a format arg" stdin: | printf "%s\n" "-v" - name: "printf -v with attached value" stdin: | printf -va "" echo "a: '${a}'" printf -vmyvar "%s, %s" "Hello" "world" echo "myvar: '${myvar}'" - name: "printf -vv with attached value" stdin: | printf -vva "value" echo "va: '${va}'" - name: "printf with no-consuming format and extra arguments" stdin: | printf "foo" bar baz qux echo printf "no specifiers\n" 1 2 3 - name: "printf format string starting with hyphen via --" stdin: | printf -- "-5\n" printf -- "%s\n" "-v" - name: "printf with hyphen-prefixed format arguments" stdin: | printf "%s\n" -5 printf "%d\n" -5 printf "%s %s\n" -a -b printf "%s\n" -v printf "%s\n" --foo printf "%s\n" - printf "x%sy\n" -abc printf "%d %d\n" -1 -2 -3 -4 - name: "printf with option-like format arguments and attached values" stdin: | printf "%s\n" "-v" "-va" "-vva" - name: "printf with -- among format arguments" stdin: | printf "%s\n" -- -x printf "%s|%s\n" a -- b printf -- "%s\n" -- x - name: "printf with hyphen-prefixed format string (invalid option)" ignore_stderr: true stdin: | printf -x echo "Result: $?" # Bash-specific %q format (shell-safe quoting) - name: "printf %q" stdin: | echo "[1]" printf "%q" 'TEXT'; echo echo "[2]" printf "%q" '$VAR'; echo echo "[3]" printf "%q" '"'; echo - name: "printf ~%q" stdin: | echo "[1]" printf "~%q" 'TEXT'; echo echo "[2]" printf "~%q" '$VAR'; echo echo "[3]" printf "~%q" '"'; echo # ================================================================= # STANDARD C PRINTF FORMAT SPECIFIERS # These should work with external printf and bash builtin printf # ================================================================= # Integer formatting tests - name: "printf %d with integers" stdin: | printf "%d\n" 42 printf "%d\n" -17 printf "%d\n" 0 - name: "printf %o (octal)" stdin: | printf "%o\n" 42 printf "%o\n" 8 printf "%o\n" 255 - name: "printf %x and %X (hex)" stdin: | printf "%x\n" 255 printf "%X\n" 255 printf "%x\n" 42 # Floating point tests - name: "printf %f (float)" stdin: | printf "%f\n" 3.14159 printf "%.2f\n" 3.14159 printf "%6.2f\n" 3.14159 - name: "printf %e and %E (scientific)" stdin: | printf "%e\n" 1234.5 printf "%E\n" 1234.5 - name: "printf %g and %G (general)" stdin: | printf "%g\n" 1234.5 printf "%G\n" 0.00012345 # Character formatting - name: "printf %c (character)" stdin: | printf "%c\n" 65 printf "%c\n" 97 printf "%c%c%c\n" 72 101 121 # Width and precision tests - name: "printf width formatting" stdin: | printf "%5s|\n" "hi" printf "%-5s|\n" "hi" printf "%05d|\n" 42 - name: "printf precision with strings" stdin: | printf "%.3s\n" "hello" printf "%10.3s\n" "hello" # Multiple arguments and reuse - name: "printf argument reuse" stdin: | printf "%s %s %s\n" "one" "two" printf "%d %d %d\n" 1 2 # Special characters and escapes - name: "printf with escape sequences" stdin: | printf "hello\nworld\n" printf "tab\there\n" printf "quote: \"\n" - name: "printf with backslash escapes" stdin: | printf "\\n\\t\\r\\\\\n" # Missing arguments (bash handles gracefully) - name: "printf missing arguments" stdin: | printf "%s %s\n" "only_one" # Empty and edge cases - name: "printf with empty format" stdin: | printf "" - name: "printf with just format string" stdin: | printf "just text\n" # Type conversion tests (safe cases only) - name: "printf valid string to number conversion" stdin: | printf "%d\n" "42" printf "%d\n" "0" - name: "printf with percent literal" stdin: | printf "100%% complete\n" printf '%%q\n' - name: "printf %b (backslash escape expansion)" known_failure: true stdin: | printf "%b\n" "hello\\nworld" printf "%b\n" "tab\\there" printf "%b\n" "quote\\\"here" - name: "printf %b with field width" known_failure: true stdin: | printf "%10b|\n" "hello\\nworld" printf "%-10b|\n" "tab\\there" - name: "printf %T (date/time formatting)" known_failure: true # Not supported by uucore stdin: | printf "%(%Y-%m-%d)T\n" 1234567890 # Test argument reuse with bash-specific formats - name: "printf %q argument reuse" stdin: | printf "%q %q %q\n" "one with spaces" "two" - name: "printf %b argument reuse" stdin: | printf "%b %b %b\n" "one\\ntwo" "three" # Test C-style constant interpretation - name: "printf with quoted character arguments" known_failure: true stdin: | printf "%d\n" "'A" printf "%d\n" '"' - name: "printf with plus/minus signs in numeric arguments" stdin: | printf "%d\n" "+42" printf "%d\n" "-17" # ================================================================= # ADDITIONAL STANDARD FORMAT SPECIFIERS # More comprehensive coverage of printf(3) man page features # ================================================================= # Additional format specifiers from man page - name: "printf %i (signed integer)" stdin: | printf "%i\n" 42 printf "%i\n" -17 - name: "printf %u (unsigned integer)" stdin: | printf "%u\n" 42 printf "%u\n" 4294967295 # Advanced width and precision - name: "printf with asterisk width and precision" stdin: | printf "%*s|\n" 10 "hello" printf "%.*s|\n" 3 "hello world" printf "%*.*s|\n" 10 3 "hello world" - name: "printf with zero precision and zero arg" stdin: | printf "%.0d\n" 0 - name: "printf with zero precision" stdin: | printf "%.0d\n" 42 # Flag characters - name: "printf with flag characters" stdin: | printf "%+d\n" 42 printf "% d\n" 42 printf "%#x\n" 255 printf "%#o\n" 64 # Left justification - name: "printf left justification" stdin: | printf "%-10s|\n" "left" printf "%-10d|\n" 42 # Zero padding - name: "printf zero padding" stdin: | printf "%010d\n" 42 printf "%010.2f\n" 3.14 # Combining flags - name: "printf combining flags" stdin: | printf "%+010d\n" 42 printf "%-+10d|\n" 42 # More precision tests - name: "printf precision with integers" stdin: | printf "%.5d\n" 42 printf "%.5o\n" 42 printf "%.5x\n" 42 # Large numbers and edge cases - name: "printf with large numbers" stdin: | printf "%d\n" 2147483647 printf "%u\n" 4294967295 printf "%x\n" 4294967295 # More character and escape testing - name: "printf with special characters" stdin: | printf "%c\n" 0 printf "%c\n" 32 printf "%c\n" 127 # Negative numbers with different formats - name: "printf negative numbers" stdin: | printf "%d\n" -1 printf "%o\n" -1 printf "%x\n" -1 printf "%u\n" -1 # Empty string handling - name: "printf with empty strings" stdin: | printf "%s|\n" "" printf "%5s|\n" "" printf "%.5s|\n" "" # More empty string handling - name: "printf with empty strings for numbers" known_failure: true stdin: | printf "%d" "" printf "%x" "" # Scientific notation edge cases - name: "printf scientific notation edge cases" stdin: | printf "%e\n" 0.0 printf "%E\n" 0.0 printf "%g\n" 0.0000001 printf "%G\n" 1000000.0 # Mixed format strings - name: "printf mixed formats in one string" stdin: | printf "Dec: %d, Hex: %x, Oct: %o, Char: %c\n" 65 65 65 65 # Field width larger than content - name: "printf wide fields" stdin: | printf "%20s|\n" "short" printf "%20d|\n" 42 # Return value testing (should always be 0 for successful printf) - name: "printf return value" stdin: | printf "test" echo " exit: $?" # Error handling tests - marked as known failures due to external printf differences - name: "printf with invalid format" ignore_stderr: true stdin: | printf "%z\n" "test" - name: "printf with no arguments" ignore_stderr: true stdin: | printf echo "Result: $?" - name: "printf string to number conversion with invalid input" known_failure: true # Need to investigate stdin: | printf "%d\n" "abc" echo "Result: $?" - name: "printf %q with empty string" stdin: | printf '%q\n' '' printf '~%q\n' '' - name: "printf -v through nameref" known_failure: true stdin: | declare -n ref=target printf -v ref "formatted %d" 42 echo "target: $target" echo "ref: $ref" - name: "printf %q with multiple args and mixed specs" stdin: | printf '%q\n' 'foo bar' printf '%q ' 'a b' '' "x'y" 'a,b' '/tmp/x-[1]/y' $'a\nb'; echo printf '%s=%q\n' k 'v w' m 'n$o' printf '~%q\n' 'a b' - name: "printf %q shell-sensitive characters" stdin: | printf '%q\n' '~' 'x:~' 'x=~' '#' 'x#y' printf '%Q\n' '~' 'x:~' 'x=~' '#' 'x#y' - name: "printf %Q" stdin: | printf '%Q\n' 'foo bar' - name: "printf %q with ignored modifier" stdin: | printf '<%2q>\n' 'foo bar' - name: "printf %q width and precision semantics" known_failure: true # Requires q/Q modifier metadata from uucore stdin: | printf '<%12q>\n' 'foo bar' printf '<%.5q>\n' 'foo bar' printf '<%.5Q>\n' 'foo bar' - name: "printf %q dynamic and positional modifiers" known_failure: true # Dynamic modifiers are unsupported; positional forms follow uucore ignore_stderr: true stdin: | printf '<%*q>\n' 12 'foo bar' printf '<%.*Q>\n' 5 'foo bar' printf '<%2$q>\n' first second - name: "printf %q alternate form" min_oracle_version: "5.3" # Alternate form forces single quoting starting in bash 5.3 stdin: | printf '<%#q>\n' 'foo bar' printf '<%#Q>\n' 'foo bar' - name: "printf %q alternate form edge cases" min_oracle_version: "5.3" # Alternate form forces single quoting starting in bash 5.3 known_failure: true # Requires alternate-form and width metadata from uucore stdin: | printf '<%#q>\n' 'foo' printf '<%#12q>\n' 'foo bar' - name: "printf %q escapes commas" stdin: | printf '%q\n' 'a,b' ',' '{a,b}' - name: "printf -v followed by --" stdin: | printf -v x -- '%s' ho echo "x=$x" printf -vy -- '%s-' -- a echo "y=$y" - name: "printf -v given more than once keeps the last" stdin: | printf -v x -v y '%s' z; echo "x=[$x] y=[$y] rc=$?" printf -vp -vq '%s' r; echo "p=[$p] q=[$q] rc=$?" - name: "printf -v leaves later option-like words as data" stdin: | printf -v x '%s,' -v y -- -x; echo "x=[$x] y=[$y]" printf -v x -- -- a; echo "x=[$x]" - name: "printf -v with no format fails" ignore_stderr: true stdin: | printf -v x; echo "rc=$?" printf -v x --; echo "rc=$?" printf -v; echo "rc=$?" - name: "printf -v with an invalid name fails with status 2" ignore_stderr: true stdin: | printf -v 1bad '%s' x; echo "rc=$?" printf -v -x '%s' x; echo "rc=$?" printf -v -- '%s' x; echo "rc=$?" printf -v-x '%s' x; echo "rc=$?" printf -v 'a b' '%s' x; echo "rc=$?" printf -v '' '%s' x; echo "rc=$?" printf -v 'a[' '%s' x; echo "rc=$?" printf -v 'a[]' '%s' x; echo "rc=$?" declare -p a 2>/dev/null || echo "a unset" # The name is checked before the format. printf -v 1bad '%d' abc; echo "rc=$?" - name: "printf -v rejects a subscript with text after its closing bracket" ignore_stderr: true stdin: | printf -v 'a[0]]' '%s' x; echo "rc=$?" printf -v 'a[0]junk]' '%s' x; echo "rc=$?" declare -p a 2>/dev/null || echo "a unset" printf -v 'a[x[1]]' '%s' x; echo "nested: rc=$?" declare -A m; printf -v 'm["]"]' '%s' x; echo "quoted: rc=$? ${m["]"]}" - name: "printf -v checks every name it is given" ignore_stderr: true stdin: | x=old; printf -v -x -v x '%s' new; echo "rc=$? x=$x" x=old; printf -v 1bad -v x '%s' new; echo "rc=$? x=$x" x=old; printf -v x -v 1bad '%s' new; echo "rc=$? x=$x" printf -v y -v x '%s' last; echo "rc=$? x=$x y=${y-unset}" - name: "printf -v doesn't evaluate a subscript to check the name" ignore_stderr: true stdin: | x=old; printf -v 'a[\]]' -v x '%s' new; echo "rc=$? x=$x" x=old; printf -v "a['x]']" -v x '%s' new; echo "rc=$? x=$x" x=old; printf -v 'a[$(echo ])]' -v x '%s' new; echo "rc=$? x=$x" x=old; printf -v 'a["x]' -v x '%s' new; echo "rc=$? x=$x" - name: "printf -v checks a subscript's brackets as an assignment does" known_failure: true # TODO(parser): an assignment's subscript must balance ( and may hold an unquoted [ ignore_stderr: true stdin: | x=old; printf -v 'a[(]' -v x '%s' new; echo "rc=$? x=$x" x=old; printf -v 'a[[]' -v x '%s' new; echo "rc=$? x=$x" - name: "printf -v takes a[@] and a[*] as names but can't assign to them" ignore_stderr: true stdin: | x=old; printf -v 'a[@]' -v x '%s' new; echo "rc=$? x=$x" x=old; printf -v 'a[*]' -v x '%s' new; echo "rc=$? x=$x" printf -v 'a[@]' '%s' v; echo "rc=$? ${a[*]-unset}" printf -v 'a[*]' '%s' v; echo "rc=$? ${a[*]-unset}" - name: "printf --help prints help on stdout" known_failure: true # TODO(printf): --help is taken for an invalid option stdin: | printf --help >/dev/null 2>&1; echo "rc=$?" [[ -n $(printf --help 2>/dev/null) ]] && echo "help on stdout" printf -v x --help >/dev/null 2>&1; echo "after -v: rc=$?" printf -- --help; echo " after --: rc=$?"