38

I have the following two lines in Perl:

print "Warning: this will overwrite existing files.  Continue? [y/N]: \n";
my $input = <STDIN>;

The problem is that the print line does not get executed before the Perl script pauses for input. That is, the Perl script just seems to stop indefinitely for no apparent reason.I'm guessing that the output is buffered somehow (which is why I put the \n in, but that doesn't seem to help).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John
  • 3,400
  • 3
  • 31
  • 47

5 Answers5

52

By default, STDOUT is line-buffered (flushed by LF) when connected to a terminal, and block-buffered (flushed when buffer becomes full) when connected to something other than a terminal. Furthermore, <STDIN> flushes STDOUT when it's connected to a terminal.

This means

  • STDOUT isn't connected to a terminal,
  • you aren't printing to STDOUT, or
  • STDOUT's been messed with.

print prints to the currently selected handle when no handle is provided, so the following will work no matter which of the above is true:

# Execute after the print.
# Flush the currently selected handle.
# Needs "use IO::Handle;" in older versions of Perl.
select()->flush();

or

# Execute anytime before the <STDIN>.
# Causes the currently selected handle to be flushed immediately and after every print.
$| = 1;
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 4
    This is a good answer, note you can also set autoflush for a specific handle `STDERR->autoflush(1);` – Andreas Louv Nov 19 '15 at 19:59
  • Indeed, but note that STDERR is auto-flushed by default. – ikegami Sep 26 '18 at 03:20
  • @ikegami - In my experience, STDERR is **not always** auto-flushed **by default**. – Ωmega Nov 11 '18 at 19:18
  • @Ωmega, For what OS and what version of Perl do you think it's not? All versions of Perl on Linux and Windows autoflush STDERR, and I'd be very surprised to find out it's OS-specific or version-specific. In fact, you can't even turn off autoflushing for STDERR. Feel free to test with `perl -E'print STDERR "foo"; sleep(5); say STDERR "bar"'` – ikegami Nov 11 '18 at 19:55
  • 1
    @ikegami - Here is a simple example: `perl -E 'use open ":std", ":encoding(UTF-8)"; print STDERR "foo"; sleep(5); say STDERR "bar"'` versus `perl -E 'use open ":std", ":encoding(UTF-8)"; STDERR->autoflush(1); print STDERR "foo"; sleep(5); say STDERR "bar"'` using *CentOS Linux release 7.5.1804 (Core)* and *Perl 5, version 16, subversion 3 (v5.16.3) built for x86_64-linux-thread-multi* – Ωmega Nov 12 '18 at 20:27
  • 1
    @Ωmega, Ah yes, while the underlying handle is autoflushed, the encoding layer adds another buffer which is not. That should be reported as a bug, IMHO – ikegami Nov 12 '18 at 22:17
16

There are several ways you can turn on autoflush:

$|++;

at the beginning, or also with a BEGIN block:

BEGIN{ $| = 1; }

However, it seems to be something unusual with your configuration, because usually a \n at the end triggers the flushing (at least of the terminal).

Diego Sevilla
  • 28,636
  • 4
  • 59
  • 87
7

To those who don't want to call flush() following every print like a baby-sitter thing, because it might be in a loop or something and you simply want your print to be unbuffered, then simply put this at the top portion of your perl script:

STDOUT->autoflush(1);

Thereafter, no need to call flush() after print.

daparic
  • 3,794
  • 2
  • 36
  • 38
2
use IO::Handle;
STDOUT->flush();
Gábor
  • 371
  • 3
  • 8
1

Yes. I made a subroutine for this in my util.pl file, which is required in all my Perl programs.

###########################################################################
# In: File handle to flush.
# Out: blank if no error,, otherwise an error message. No error messages at this time.
# Usage: flushfile($ERRFILE);
# Write any file contents to disk without closing file. Use at debugger prompt
# or in program.
sub flushfile
{my($OUTFILE)=@_;
my $s='';

my $procname=(caller(0))[3]; # Get this subroutine's name.

my $old_fh = select($OUTFILE);
$| = 1;
select($old_fh);

return $s; # flushfile()
}

Bulrush
  • 548
  • 2
  • 4
  • 19