I/O

close#

Close a filehandle, flush its buffers, and release the underlying file descriptor.

close finishes whatever I/O was pending on FILEHANDLE, tears down the PerlIO layer stack, and asks the kernel to close the descriptor. The return value distinguishes a clean shutdown from one where either a buffered write failed on the way out, a PerlIO layer reported an error, or — for pipes — the child process exited non-zero. Without an argument, close operates on the currently selected filehandle (see select).

Synopsis#

close FILEHANDLE
close EXPR
close

What you get back#

Truthy (1) on a clean shutdown; false otherwise. A false return means one of the following went wrong:

  • A pending buffered write could not be flushed (disk full, broken pipe, closed socket).

  • A PerlIO layer (e.g. :encoding(...), :gzip from a CPAN layer) reported an error.

  • A pre-existing sticky error was already recorded on the handle.

  • The handle came from a piped open and the child exited non-zero (or another syscall involved in tearing the pipe down failed).

When close returns false, $! holds the error from the failing operation and is safe to read. For pipe handles, if the only problem was a non-zero child exit, $! is set to 0 and the child’s status shows up in $? (see below).

Always check the return value on writable handles: the final buffered block is flushed inside close, so print returning true earlier does not guarantee the data reached disk.

close $fh
    or die "close $path failed: $!";

Global state it touches#

  • $! — set to the failing errno when close returns false, including the flush error on the final buffered write. Cleared to 0 on a pipe close where the only problem was a non-zero child exit.

  • $? — for handles from a piped open, set to the wait status of the child process: low 8 bits are the signal, high 8 bits are the exit code (same encoding as system).

  • ${^CHILD_ERROR_NATIVE} — for pipe handles, set to the raw OS-native status value (before Perl’s portable encoding).

  • $. — an explicit close on an input handle resets the current line number. An implicit close via reopening the same handle does not.

  • Currently selected filehandle (via select) — close with no argument closes it.

Examples#

Close a regular file and check for a flush failure:

open my $fh, ">", "out.txt" or die $!;
print {$fh} @records;
close $fh or die "flush to out.txt failed: $!";

Close a pipe opened for writing and inspect the child’s exit status. close waits for the child, then populates $?:

open(my $sort, "|-", "sort", ">", "foo")
    or die "can't start sort: $!";
# ... print records to $sort ...
close $sort
    or warn $! ? "error closing sort pipe: $!"
               : "sort exited with status " . ($? >> 8);

Close a pipe opened for reading, then collect the command’s exit status. Exit code is the top 8 bits of $?:

open(my $who, "-|", "who") or die $!;
my @lines = <$who>;
close $who;
my $exit = $? >> 8;

Bare close closes whatever handle select most recently made current, then restores STDOUT as the selected handle:

open my $log, ">>", "app.log" or die $!;
my $old = select $log;
print "entry\n";
close;                       # closes $log (the selected handle)
select $old;

Closing the read end of a pipe early makes the writer receive SIGPIPE. If the writer has no handler, it will be killed — drain the pipe first if you need the writer to exit cleanly:

open my $gen, "-|", "some-producer" or die $!;
while (<$gen>) { last if /^END/ }
1 while <$gen>;              # drain so the child finishes cleanly
close $gen or warn "producer failed: $!";

Edge cases#

  • Bare close — with no argument, closes the currently selected filehandle. In a freshly started program that is STDOUT; after a select($fh) it is $fh. Rarely what you want outside tightly scoped code.

  • Reopening closes for youopen my $fh, ... on a handle that is already open will close the old descriptor first. The implicit close does not reset $.; an explicit close does. Use an explicit close when line-number state matters.

  • Scope exit closes lexical handles — when the last reference to a lexical filehandle goes out of scope, Perl closes it. If that implicit close fails (flush error, child exit non-zero), Perl emits a Warning: unable to close filehandle %s properly warning. Call close explicitly at a point where you can check the return value and silence that warning.

  • Indirect handlesFILEHANDLE may be any expression producing a usable filehandle: a bareword (close STDERR), a scalar (close $fh), a glob ref (close \*FH), or an autovivified handle from open my $fh, ....

  • Pipe close waits — closing a pipe handle blocks until the child exits, so $? is populated by the time close returns. Under threads, if the same pipe handle is still open in another thread, close returns true immediately without reaping the child.

  • Pipe close with non-zero exitclose returns false and sets $! to 0 so that $! ? "$!" : "exit $?" discriminates between an OS-level failure and an ordinary non-zero exit.

  • Closed or invalid handle — closing a handle that is not open sets $! to "Bad file descriptor" and returns false. Under use warnings, a close() on unopened filehandle warning is emitted.

  • STDIN / STDOUT / STDERR — can be closed like any other handle. The descriptor is freed and will be reused by the next open on the standard handle, which is how the classic open STDOUT, ">", "log" redirect works.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • open — counterpart; an open on an already-open handle does an implicit close first (but does not reset $.)

  • print — final buffered print is flushed inside close, so the write’s real success is only known after close

  • fileno — descriptor number of a handle; becomes invalid once close succeeds

  • binmode — layer stack set by binmode is torn down during close, and its teardown can itself fail

  • $? — child exit status populated by close on a pipe handle

  • $! — error from the failing close operation