2

I have this piece of code:

#!/usr/local/bin/perl
use strict;
open my $output, ">", "D:\\abc.txt";
for ( my $i = 0; $i < 10; $i++ )
{
    print $output $i . "\n";
    sleep(5);
}

Surprisingly, when I run it and open abc.txt in the 50 seconds while the machine is running, I don't see the current output. I would expect that after 13 seconds, for example, the file would include "0\n1\n2", but it doesn't, for some reason.

I reviewed other pieces of code which I wrote and actually do that, but I couldn't find any difference.

Can you please help me?

Thank you in advance.

Amy
  • 23
  • 2
  • 1
    This question has been asked many times before. Please search before posting a question. – Zaid Jul 27 '11 at 17:27
  • 1
    possible duplicate of [Sleep function in Perl](http://stackoverflow.com/questions/6558634/sleep-function-in-perl) – Zaid Jul 27 '11 at 17:34
  • An alternative to using double backslashes `\\ ` for windows paths is forward slash `/`: `"D:/abc.txt"`. You may also consider `'D:\abc.txt'` – TLP Jul 27 '11 at 17:34
  • Zaid - Thank you for your answer. I'm very sorry, I simply did not know what to search for. As said, for some reason setting $| to 1 doesn't solve the problem. TLP - Thanks a lot, I'll keep that in mind. – Amy Jul 27 '11 at 17:46
  • 1
    So, how do you know you even opened the file successfully? I don't see any checking of the return value of `open`. Similarly, how do you know that `print` worked? – jrockway Jul 27 '11 at 17:50
  • I know all of these actions were successful because after the machine stops running, I open abc.txt and see 0\n1\n2\n3\n4\n... – Amy Jul 27 '11 at 17:54
  • 1
    It's been asked many times, and is even in perlfaq5. But more often than not I see people forgetting that $| does not universally apply to all filehandles. Even in quick responses here that fact seems to get overlooked soemtimes. One must select the filehandle to which it should be applied. – DavidO Jul 27 '11 at 19:20
  • You're [suffering from buffering](http://perl.plover.com/FAQs/Buffering.html). – Dave Cross Jul 27 '11 at 17:39

1 Answers1

6

If you read Marc Jason Dominus's article, Suffering from Buffering you will see that setting $| applies to the current filehandle. If you set $| = 1; near the top of your script, you're probably turning off buffering for STDOUT. Yet your script is writing to a filehandle named $output.

You should put this line in your script immediately following the open call.

select( ( select( $output ), $|=1 )[0] ); # borrowed from the Suffering from Buffering article.

This trick selects the $output filehandle, turns buffering off, then reselects the originally selected filehandle (presumably STDOUT) so that the rest of your script doesn't start using $output unknowingly.

This is also documented in perlfaq5, which comes standard with every complete Perl installation.

As a best practice, you probably should also either be putting or die $! after all IO calls, or use autodie; at the top of your script. I say 'probably' because there are always exceptions, but it's unlikely that this is one of them.

DavidO
  • 13,812
  • 3
  • 38
  • 66
  • Hi David - thank you so much for your answer, that was the problem. I am so sorry that I didn't see it myself in the article, I was only reviewing it because I thought it suggested the same solution as the others have. I still don't understand why, then, I didn't have to put that in my other codes... – Amy Jul 27 '11 at 21:26
  • Without seeing other code it would only be a guess. But Perl does flush output buffers when they fill up, when their filehandle is closed (including upon program termination, or when a lexical filehandle passes out of scope), and in the case of terminal output, upon encountering a newline character. If the answer worked, accept. ;) – DavidO Jul 27 '11 at 21:33
  • Yes, I did realise that when encountering a newline character, Perl flushes - this is why I found the example in my question so strange, because it does use a newline character! Yes, the answer did worked, and I did accept. :-) – Amy Jul 27 '11 at 21:41
  • 1
    The newline autoflush applies to terminal streams (STDOUT to a terminal). ...and thanks. :) – DavidO Jul 27 '11 at 21:49