tell#
Return the current byte position of a filehandle.
tell reports where the next read or write on FILEHANDLE will
happen, measured in bytes from the start of the file. Pair it with
seek to save a position now and return to it later. If
FILEHANDLE is omitted, tell reports the position of the handle
last read from — including the implicit handle inside while (<FH>)
loops.
Synopsis#
tell FILEHANDLE
tell
What you get back#
A non-negative integer byte offset on success, -1 on error. The
value is suitable as the POSITION argument to seek with
WHENCE set to 0 (absolute seek). On pipes, FIFOs, sockets, and
sometimes on the standard streams, the underlying OS has no seekable
position and tell returns -1; $! is not necessarily
set in that case, so treat -1 as the authoritative failure signal.
my $pos = tell $fh;
die "not a seekable handle" if $pos < 0;
# ... read or write ...
seek $fh, $pos, 0; # back to where we were
Global state it touches#
Last-read filehandle: the no-argument form
telluses the handle most recently read from in the current scope. Everyreadline,<FH>, or<>updates this. Mixingtellwith no argument and multiple active handles is a source of surprising results — name the handle explicitly when in doubt.$!is not a reliable error channel here. Check for-1directly rather than testing$!after the call.
Bytes, not characters#
tell always returns a byte offset, even when the handle has a
character-oriented PerlIO layer such as :encoding(UTF-8) or :utf8.
This is deliberate: translating a character count into a byte offset
in a variable-width encoding would require rereading the file from
the beginning. The same rule applies to seek and
sysseek — they all speak bytes.
Consequence: on a UTF-8 text file you cannot in general use tell to
count characters. Use it only to mark a position you intend to feed
back into seek.
Examples#
Remember a position, read ahead, return:
open my $fh, "<", "log.txt" or die $!;
my $mark = tell $fh; # 0
my $first = <$fh>; # read one line
seek $fh, $mark, 0; # rewind to the mark
my $again = <$fh>; # same line again
Record the end-of-header offset so later code can rescan the body without reparsing the header:
while (my $line = <$fh>) {
last if $line =~ /^\r?\n\z/; # blank line ends headers
}
my $body_start = tell $fh;
# ... process body ...
seek $fh, $body_start, 0; # second pass over the body
The no-argument form uses the handle last read from. Inside a
while (<>) loop that handle is the implicit ARGV:
while (<>) {
print "at ", tell, ": $_"; # offset within the current file
}
tell on a pipe returns -1 because pipes are not seekable:
open my $ph, "-|", "ls" or die $!;
my $pos = tell $ph; # -1
Filehandles inside complex expressions need the same block form as
with print — tell $handles[0] is a syntax error. Use:
my @handles = (\*STDIN, $fh);
my $pos = tell { $handles[1] };
Edge cases#
Closed filehandle: returns
-1. Underuse warningsatell() on closed filehandlewarning is emitted.No-argument form, nothing read yet: returns
-1. The “last-read filehandle” is only meaningful after an actual read.After
sysread/syswrite/sysseek: do not usetellon a handle you have manipulated with thesys*family. Those functions bypass PerlIO buffering;tellreports the buffered position, which will be wrong by the buffer contents. Usesysseekwith a whence of1and an offset of0as thesys*-safe position query.Standard streams:
tell STDIN,tell STDOUT,tell STDERRmay return-1or a meaningful offset depending on whether the stream is backed by a regular file (shell redirection) or a terminal, pipe, or socket.No
systell: there is no separate function for buffered-bypassing position. The idiom is:my $pos = sysseek $fh, 0, 1;
Binary-mode vs text-mode on non-Linux platforms: pperl targets Linux only, so
telloffsets always match raw file bytes. CRLF translation layers that complicatetellon Windows-family perls do not apply here.Append mode (
>>): afteropen my $fh, ">>", ..., the initialtell $fhmay report0until the first write, because some platforms position the handle at end-of-file only at each write. Don’t rely on the initial position; write once, thentell.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
seek— jump to an absolute byte offset previously returned bytellsysseek— position query and jump for handles used withsysread/syswrite, bypassing PerlIO bufferingeof— test for end-of-file rather than absolute positionopen— produce the filehandle in the first place; mode and PerlIO layers determine whether the handle is seekable