I/O

printf#

Write a formatted string to a filehandle.

printf is print FILEHANDLE sprintf(FORMAT, LIST) with one deliberate exception: the output record separator $\ is not appended. The targeting rules are otherwise the print rules — bareword or simple-scalar filehandle immediately before the argument list, or the {EXPR} block form for anything more complex. If FILEHANDLE is omitted, output goes to the currently selected handle (see select), which starts life as STDOUT.

See sprintf for the format-specifier reference — everything %d, %s, %.3f, %*d, %1$s, %v, vector flags, locale-sensitive %f, and so on. This page covers only the printf-specific surface: filehandle resolution, the format-is-first rule, and the quirks around the no-argument form.

Synopsis#

printf FORMAT, LIST
printf FILEHANDLE FORMAT, LIST
printf {EXPR} FORMAT, LIST
printf FH                      # bareword filehandle, $_ as format

What you get back#

1 on success, undef on failure (with $! set). As with print, the return value is rarely checked for writes to STDOUT / STDERR, and worth checking for writes to files, pipes, and sockets where partial writes and broken pipes matter.

printf $fh "%-20s %8d\n", $name, $count
    or die "write to $path failed: $!";

Global state it touches#

  • Selected filehandle (changed via select): the destination when FILEHANDLE is omitted. Starts as STDOUT.

  • $\ (output record separator): deliberately not appended — this is the one semantic difference between printf FORMAT, LIST and print FILEHANDLE sprintf(FORMAT, LIST). Put the newline in the format string.

  • $, (output field separator): not consulted. printf splices list elements into the format according to the conversions, not with a separator.

  • $_: used as the format when both FORMAT and LIST are omitted, not appended to output. Almost never what you want; see Edge cases.

  • $!: set on write failure.

  • $|: autoflush flag for the selected handle. printf buffers through PerlIO like print.

  • LC_NUMERIC locale: when use locale is active and POSIX::setlocale has been called, the decimal separator for floating-point conversions (%f, %e, %g) follows the locale.

Examples#

Basic formatted write to STDOUT. Unlike say or print-with-$\, the trailing newline is on you:

printf "%s is %d years old\n", $name, $age;

Width and precision for a tidy column:

printf "%-20s %8.2f\n", $item, $price;

Write to a filehandle. Bareword and simple scalar work directly; no comma between the filehandle and the format:

open my $fh, ">", "report.txt" or die $!;
printf $fh "%5d  %s\n", $n, $msg;
close $fh;

Filehandle held in a more complex expression — use the {EXPR} block form (same rule as print):

my @logs = (\*STDOUT, \*STDERR);
printf { $logs[$severity] } "[%s] %s\n", $tag, $msg;

Repeated format with a list that spans multiple records. printf does not re-apply the format per record — conversions are consumed once, left to right:

printf "%s=%s\n", "user", "alice";       # "user=alice\n"
printf "%s=%s\n%s=%s\n",                 # two records, one call
       "user", "alice", "host", "db1";

Locale-sensitive decimal separator:

use POSIX qw(setlocale LC_NUMERIC);
use locale;
setlocale(LC_NUMERIC, "de_DE.UTF-8");
printf "%.2f\n", 1234.5;                 # "1234,50\n"

Edge cases#

  • No LIST given, $_ becomes the format. printf; and printf FH; (bareword filehandle) format $_. If $_ contains any % conversions they expand against an empty argument list — each %s / %d becomes the empty string and use warnings emits a Missing argument in printf warning. To write $_ verbatim use print, not printf.

  • Indirect filehandle without a list is ambiguous and not supported. printf $fh; parses $fh as the format, not the filehandle. If you need a no-argument form with a scalar filehandle, go through print or pass an explicit format: printf $fh "%s", $_.

  • The first argument is always the format. printf(@_) uses $_[0] as the format and the remaining elements as arguments — this is a parsing rule, not a convention. Build the format deliberately; don’t splat user-supplied lists into printf unless the first element is known-safe.

  • No $\ is appended. Embedding "\n" in the format is the idiomatic terminator. Setting local $\ = "\n" has no effect on printf output.

  • $, is ignored. The output field separator is a print concept; printf joins nothing — it substitutes.

  • printf (…) parses as a function call, just like print. printf ("%d", 1)*2 computes printf(...) then multiplies the return value by 2 and discards it. Wrap the whole argument list in parens or prefix with + if you need to disambiguate.

  • Closed filehandle: returns undef and sets $! to "Bad file descriptor". Under use warnings a printf() on closed filehandle warning is emitted.

  • Encoding layers: printf writes through the handle’s PerlIO stack. A :utf8 or :encoding(...) layer encodes on the way out; a bytes-mode handle with a wide-character string emits Wide character in printf and writes raw codepoints.

  • SIGPIPE on closed pipe/socket: default action terminates the process. Install $SIG{PIPE} to turn it into a checkable write failure.

  • Don’t use printf where print suffices. printf "%s", $msg is slower and more error-prone than print $msg — the format string is parsed on every call, and a stray % in $msg used as a format becomes a bug waiting to happen.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • print — unformatted write with the same filehandle rules; faster, and appends $\ where printf does not

  • sprintf — build the formatted string without writing it; the format-specifier reference lives here

  • sayprint with $\ forced to "\n"; reach for it when every record ends in a newline

  • select — change which filehandle the no-filehandle form of printf writes to

  • $\ — output record separator; deliberately not appended by printf

  • $_ — used as the format when both FORMAT and LIST are omitted