rubyguides

Kernel#printf

printf(format_string [, arguments...]) -> nil

The printf method outputs a formatted string to STDOUT. It uses format specifiers similar to C’s printf function, allowing precise control over how numbers, strings, and other values are displayed.

Basic format specifiers

# %d - Integer
printf("%d", 42)        # => 42

# %f - Float
printf("%.2f", 3.14159) # => 3.14

# %s - String
printf("%s", "hello")   # => hello

# %x - Hexadecimal
printf("%x", 255)       # => ff
printf("%X", 255)       # => FF

# %o - Octal
printf("%o", 64)        # => 100

# %b - Binary
printf("%b", 10)        # => 1010

This block shows the core format codes first so the pattern is easy to recognize. Once you know the basic specifiers, the rest of the method is mostly about choosing the right width, precision, or base for the value you want to print. The six codes above — %d, %f, %s, %x, %o, and %b — cover the most common output formats you will need in day-to-day Ruby scripts.

Width and precision

# Minimum width
printf("%5d", 42)       # => "   42"
printf("%-5d", 42)      # => "42   "

# Precision for floats
printf("%.3f", 3.14159) # => 3.142
printf("%.0f", 3.7)    # => 4

# Minimum and maximum width
printf("%8.2f", 3.14)   # => "    3.14"

Width and precision become useful when the same output needs to line up across several rows. That is why printf is often a better fit than interpolation when the final text has to look consistent in a report or table. The width specifier also lets you left-justify values with the - flag, which is handy for column headers and labels.

Multiple arguments

# Multiple values
printf("Name: %s, Age: %d", "Alice", 30)
# => Name: Alice, Age: 30

printf("%d + %d = %d", 1, 2, 3)
# => 1 + 2 = 3

Passing several arguments keeps the template compact while still making the order explicit. Each placeholder documents exactly where the next value belongs, which makes the call easy to scan for anyone reading the code later. When you have more than two or three values, the format string approach stays readable where string concatenation would become unwieldy.

Practical examples

Table formatting

# Align columns
printf("%-15s %10s\n", "Product", "Price")
printf("%-15s %10.2f\n", "Apple", 1.50)
printf("%-15s %10.2f\n", "Banana", 0.75)
printf("%-15s %10.2f\n", "Cherry", 12.99)

# Output:
# Product                   Price
# Apple                     1.50
# Banana                    0.75
# Cherry                   12.99

The spacing matters more than the individual values here. A table is easier to read when the columns stay aligned, and printf keeps that alignment in the format string instead of scattering it through the code. The \n at the end of the template is important — without it, successive printf calls would run together on the same line, undoing the visual structure you built.

Hex dump

# Memory dump style output
data = [72, 101, 108, 108, 111]  # "Hello"
data.each { |b| printf("%02X ", b) }
# => 48 65 6C 6C 6F 

This style is useful when the output is meant for humans who are reading raw values. The format string keeps every byte in the same width, which makes patterns easier to spot in the output. Two-digit hex display with %02X is a common convention for memory dumps, network packet inspection, and debugging binary data.

Number formatting

# Thousand separators
printf("%,d", 1234567)  # => 1,234,567

# Percentage
printf("%.1f%%", 0.75) # => 75.0%

# Scientific notation
printf("%.2e", 1234)   # => 1.23e+03

When you need a very specific numeric shape, printf is often clearer than building that shape by hand. The format code names the exact presentation rule, so the reader can tell whether the output is padded, rounded, or switched into scientific notation. These same specifiers also appear in sprintf and String#%, so learning them once pays off across several Ruby formatting methods.

Padding with zeroes

printf("%05d", 42)     # => 00042
printf("%08.2f", 3.14) # => 00003.14

Zero padding is common for identifiers and counters, where the width helps values line up without changing their meaning. It is a small detail, but it often makes logs and reports easier to sort by eye. Fixed-width fields also help when the output will be parsed by another program that expects a known column layout every time.

Using named arguments (Ruby 2.6+)

printf("%{name} is %{age} years old", name: "Bob", age: 25)
# => Bob is 25 years old

Named arguments keep the call site readable when the placeholders do not follow a natural left-to-right order. The names make it obvious which value fills each slot, which is useful in longer or more formal messages where the template and the data are several lines apart.

Comparison with other output methods

puts "hello"   # Adds newline
print "hello"  # No newline
printf "hello" # With formatting

# printf returns nil
result = printf("Value: %d", 42)
puts result    # => nil

This comparison is useful because it shows the boundary between output and return value. printf writes formatted text directly, but it still returns nil, so callers should not expect to chain a useful object from it. The contrast with puts and print also helps when you are choosing the right output method for a particular line.

Special characters

# Escape sequences
printf("Tab:\tNext\n")
printf("Newline:\nDone\n")

# Literal percent sign
printf("100%% complete\n")  # => 100% complete

Escaping the percent sign is the last small detail that makes the syntax feel complete. Once you know how to print a literal percent, you can use the rest of the formatting language without worrying that the symbol itself will be treated as a placeholder.

The printf method is powerful for creating formatted output, especially when you need precise control over number formatting, alignment, or table-like displays. It is most helpful when the shape of the output matters as much as the values themselves.

formatting output deliberately

printf is best when the output has a shape you want to preserve, such as a table, a report, or a line of numeric data that needs consistent spacing. The format string makes the layout explicit, which is useful when the same line will be read by a human or another program. That clarity is the main reason to choose printf instead of stitching together several smaller strings.

Because the format codes are strict, the call site should stay easy to scan. A short template with a few arguments is usually much easier to maintain than a large, hard-to-read interpolation block. When the output only needs casual text, a simpler method may be clearer, but when the shape matters, printf gives you that control directly.

The examples above move from simple placeholders to more structured output so the formatting rules build on each other. That progression makes it easier to choose the right specifier instead of guessing at the syntax when you need one more column or one more decimal place.

keeping templates easy to scan

A good format string does not try to hide the structure of the output. It should be short enough that the reader can see the fields, their order, and any alignment or precision settings without hunting through the line. That makes printf especially useful for logs and reports that must stay consistent over time. When the template starts to grow complex, it can be a sign that the output should be broken into a few clearer lines instead.

See Also