I/O

write#

Render one record to a filehandle through its associated format.

write is the executor half of Perl’s report-generation mechanism: it takes the picture declared by a format, plugs the values from the matching argument lines into the fields, and emits the resulting lines to FILEHANDLE. It also tracks the page: when not enough lines remain, it writes a form feed, runs the top-of-page format, and then writes the record. write is the only way a declared format produces output; a format is inert until write references it.

Do not confuse this with syswrite or the inverse of read: write is strictly the picture-record executor. It has nothing to do with raw byte output.

Synopsis#

write FILEHANDLE
write EXPR
write

What you get back#

1 on success, undef on failure (with $! set). A failure here is typically either a closed handle or an I/O error on the underlying write — not “format not found,” which croaks rather than returning undef.

How write picks the format#

Every filehandle has two format slots: the record format and the top-of-page format. By default:

  • The record format is the format whose name matches the filehandle (format STDOUT for STDOUT, format REPORT for a handle opened as REPORT).

  • The top-of-page format is the filehandle name with _TOP appended (STDOUT_TOP, REPORT_TOP), falling back to top in the current package.

Both are overridable per-handle through $~ (current format name) and $^ (current top-of-page format name). These variables act on the currently selected handle, so changing them for anything other than STDOUT requires a select dance:

my $ofh = select REPORT;
$~ = "My_Format";
$^ = "My_Top";
select $ofh;

If FILEHANDLE is omitted, write targets the currently selected handle (default STDOUT). If the argument is an EXPR rather than a bareword, the expression is evaluated and its string value is looked up as the filehandle name at runtime.

Global state it touches#

write reads and updates a cluster of per-handle format variables. All are per-filehandle, reached via select:

  • $~ — name of the record format for the selected handle. Read at every write call.

  • $^ — name of the top-of-page format. Consulted when a new page begins.

  • $= — page length in lines. Default 60.

  • $- — lines remaining on the current page. Decremented by every write. Set to 0 to force a page break on the next call.

  • $% — current page number. Incremented on each top-of-page.

  • $^L — string emitted before every top-of-page except the first. Default "\f" (form feed).

  • $: — characters on which fill-mode (^) fields may break.

  • $^A — the format accumulator, the buffer formline writes into and write flushes. Rarely touched directly unless you are bypassing write with formline.

write also writes through the PerlIO stack of the target handle, so $| (autoflush on the selected handle) still applies.

Top-of-form processing#

Before emitting the record, write checks whether the record fits in the lines remaining on the page ($-). If it does not:

  1. Emit $^L (form feed by default) — skipped on the very first page.

  2. Run the top-of-page format named by $^ to produce the page header.

  3. Reset $- to $= and increment $%.

  4. Emit the record.

On the very first write to a handle, step 1 is skipped so the output does not begin with a form feed.

Examples#

Basic report with a header:

format STDOUT_TOP =
                        Passwd File
 Name                Login    Office   Uid   Gid Home
 ------------------------------------------------------------------
.
format STDOUT =
 @<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<<
 $name,              $login,  $office,$uid,$gid, $home
.

while (my @row = getpwent) {
    ($name, $login, $uid, $gid, $office, $home) = @row[0,0,2,3,5,7];
    write;
}

Write to a named filehandle. The format name defaults to the handle name; no select is needed if the default is acceptable:

open my $fh, ">", "report.txt" or die $!;
format REPORT =
 @<<<<<<<<<<<<<<   @>>>>>>>
 $item,            $count
.
# rebind the glob so REPORT refers to $fh
*REPORT = *$fh;
for my $r (@records) {
    ($item, $count) = @$r;
    write REPORT;
}
close $fh;

Switch format at runtime by setting $~ on the selected handle. local confines the change to the current scope:

sub print_summary {
    local $~ = "SUMMARY_FORMAT";
    write;
}

Force a page break by zeroing $- before the next call:

$- = 0;                  # next write starts a new page
write;

write EXPR picks the handle at runtime from a string — useful when the target is data-driven:

my $handle_name = $verbose ? "LOG" : "STDOUT";
write $handle_name;

Interleaving print with write: legal, but $- only tracks write output. If a print burst consumes page rows you care about, decrement $- by hand:

print "extra note: $msg\n";
$-  -= 1;                 # keep the page counter honest
write;

Edge cases#

  • Format not found: if the format named by $~ does not exist, write croaks with Undefined format "NAME" called. This is a fatal error, not a return-undef-with-$! failure.

  • Closed filehandle: returns undef and sets $!. Under use warnings a write() on closed filehandle warning is emitted.

  • Record taller than page: if the record itself has more lines than $=, write still emits all of its lines on one page — it does not split a single record across a page boundary. The oversize is silently tolerated.

  • _TOP fallback: if no <HANDLE>_TOP format exists, write falls back to the format named top in the current package. This is rarely what you want for autovivified handles; set $^ explicitly when it matters.

  • Lexical variables in formats: my variables declared outside a format are not visible inside it unless the format is declared within the lexical scope of those variables. This bites anyone who wraps write inside a subroutine and wonders why the report is blank — move the format declaration inside the sub, or use package globals for the argument-line expressions.

  • Top-of-page triggers mid-record, not mid-page: write checks page room once per record. A record that starts near the bottom of the page will either fit in full or trigger top-of-page before being written; it never straddles.

  • LC_NUMERIC and numeric fields: if use locale is in effect when the format is declared, the decimal point in numeric fields follows the locale at declaration time — not at write time. Switching locales after the format is compiled does not change the separator.

  • Control characters in text fields are replaced with spaces so they cannot scramble column alignment. The sole exception is \r in fill-mode fields, where it forces a line break.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • format — declare the picture that write renders; the two are meaningless without each other

  • formline — run one picture line against an argument list into $^A without any page tracking; the low-level primitive behind write

  • select — change which handle write targets when called without an argument, and the prerequisite for setting any of the $~, $^, $=, $- per-handle

  • print — free-form output when columnar reporting is overkill; may be interleaved with write on the same handle

  • $~ — override the record format name for the selected handle

  • $- — lines left on the current page; set to 0 to force a new page before the next write

  • perlform.pod — full picture-line grammar, fill-mode rules, and worked report examples