4

My code won't run the last line right before " exit; " and I have no clue why. I tried to put an additional printf $fh line before exit, but that didn't work either; it would not print either line. Everything else prints fine except the last print statements before the exit.

Any clue why this happens? Or better yet, how to fix or work around it?

    if($i>0 && $i<3)
    {
        printf $fh "Partial match found.\n";
        if($matched_uid){printf $fh "UID #: ".$arguid." exists.\n";}
        if($matched_id){printf $fh "ID #: ".$argid." exists.\n";}
        if($matched_uname){printf $fh "Username: ".$arguname." exists.\n";}
        printf $fh "Aborting."; 
        exit;
    }

EDIT:
Part of the code I copied contained this

select $fh; $| = 1; #set auto flush

Maybe this is why my results couldn't be duplicated....

4

6 回答 6

10

I gave R. Bemrose my vote, but if $fh is a FILE HANDLE you may want to also close it prior to terminating.

Also, you are using printf wrongly. printf is not 'print file'. its 'print format'.

For that last example

  print $fh 'Message' ;  

Is all you need.

printf is intended to be used thus:

printf $fh 'some format %s  and more %s ' ,  $var , $var ; 

or

   printf 'some format %s  and more %s ' ,  $var , $var ; 

and its equivelant to doing

   print $fh sprintf 'format %s more %s' , $var , $var ; 

And because of this, you're putting needless code risks in in the event any of your concatenated variables expand to have '%' in them. For an example of people falling into this trap, see Q:308417:Why does my Perl script remove characters from the file?

perldoc -f print

print FILEHANDLE LIST
print LIST
print   Prints a string or a list of strings.

perldoc -f printf

printf FILEHANDLE FORMAT, LIST
printf FORMAT, LIST
      Equivalent to "print FILEHANDLE sprintf(FORMAT, LIST)", except that "$\" 
      (the output record separator) is not appended

Further Probing

I've been probing into your problem further because I can't get your "buffering" condition to occur. All my files are properly flushed whether or not I flush them. ( Perl 5.10 ).

Heres my code snippet I'm trying:

#!/usr/bin/perl 

use strict;
use warnings;


open my $fh , '>' , '/tmp/oo.txt'; 

my $exit_at = int(rand( 200_000 ));
print "$exit_at\n";
sleep 2;
for ( 0 .. ( $exit_at * 2 ) ){ 
    print $fh $_;
    if ( $_ == $exit_at ){
        printf $fh '%n' ; # Bad Code Causes Early Death. 
        printf $fh 'last line';
        exit; 
    }
    if ( $_ % 1000  ){
        print $fh "\n";
    }
}

I'm using your miss-use of printf. The line that is commented ejects an error message, because its not valid due to nobody providing the 'n' parameter, and it dies with:

Modification of a read-only value attempted at iotest.pl line 15.

Before executing 'last line' print ( also bad, but theres no % symbols in it so its fine ) making 'last line' absent from the output file.

Please fix up your printf and use plain-old-print instead and see if that solves your problem.

于 2009-03-11T20:02:37.963 回答
9

Perl buffers its output. You can turn off autobuffering with

local $| = 1;

Edit: I somehow hit ! instead of | the first time... fixed. No idea how that happened, they're on opposite sides of the keyboard.

于 2009-03-11T19:58:32.403 回答
8

Try "Aborting.\n"

This looks like a buffering issue.

于 2009-03-11T19:57:26.680 回答
3

On the subject of proper use of print, you make things a little hard on yourself.

Interpolate your variables instead of concatenating the strings together. Use one print statement with a list of strings to print, instead of multiple strings.

Here's one way:

if( $i>0 && $i<3 )
{
    print $fh join "\n", 
        "Partial match found.",
        $matched_uid   ? "UID #: $arguid exists."      : (),
        $matched_id    ? "ID #: $argid exists."        : (),
        $matched_uname ? "Username: $arguname exists." : (),
        "Aborting.",
        ;

    exit;
}

The () on the false side of the ternary operator is an empty list, which will disappear when the arguments to join are flattened. If I had used and empty string (''), each non-matching criterion would have produced an extra blank line in the results.

You could also add your own newline on each item, and then skip the join, if you feel this is more readable:

    print $fh  
        "Partial match found.\n",
        $matched_uid   ? "UID #: $arguid exists.\n" : '',
        ...
于 2009-03-12T05:09:23.860 回答
2

You need to add a trailing \n to the last printf. Otherwise the output doesn't get flushed to the console.

于 2009-03-11T19:58:07.473 回答
0

Either David Norman is right, or the problem is somewhere else. I just typed the code inside the if block into the perl interpreter, and it printed "Aborting." as expected. (It worked for me even without the terminating newline character.)

于 2009-03-11T20:01:31.787 回答