Почему Perl не печатает последний текст до его выхода? - PullRequest
4 голосов
/ 11 марта 2009

Мой код не будет запускать последнюю строку прямо перед "exit;", и я понятия не имею, почему. Я пытался поставить дополнительную строку printf $fh перед exit, но это тоже не сработало; это не будет печатать ни одну строку. Все остальное печатается нормально, кроме последних операторов печати перед выходом.

Любая подсказка, почему это происходит? Или еще лучше, как исправить или обойти это?

    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:
Часть кода, которую я скопировал, содержала это

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

Может быть, поэтому мои результаты не могут быть дублированы ....

Ответы [ 6 ]

10 голосов
/ 11 марта 2009

я дал р. Bemrose мой голос, но если $ fh это FILE HANDLE , вы можете также close его до завершения.

Кроме того, вы используете printf неправильно. printf это , а не 'файл печати'. его «формат печати».

Для этого последнего примера

  print $fh 'Message' ;  

Это все, что вам нужно.

printf предназначен для использования таким образом:

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

или

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

и его эквивилант к выполнению

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

И из-за этого вы рискуете ненужным кодом в случае, если какая-либо из ваших объединенных переменных будет расширена до «%». Пример людей, попавших в эту ловушку, см. Q: 308417: Почему мой Perl-скрипт удаляет символы из файла?

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

Дальнейшие исследования

Я продолжал исследовать вашу проблему, потому что не могу получить ваше состояние "буферизации". Все мои файлы правильно очищены, независимо от того, очищаю я их или нет. (Perl 5.10).

Вот мой фрагмент кода, который я пытаюсь:

#!/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";
    }
}

Я использую ваше неправильное использование printf. Закомментированная строка выводит сообщение об ошибке, потому что оно недопустимо из-за того, что никто не предоставил параметр 'n', и умирает с:

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

Перед выполнением печати «последней строки» (тоже плохо, но в ней нет символов%, так что все в порядке), так как «последняя строка» отсутствует в выходном файле.

Пожалуйста, исправьте ваш printf и используйте вместо него обычный старый принт и посмотрите, решит ли это вашу проблему.

9 голосов
/ 11 марта 2009

Perl буферизует свой вывод. Вы можете отключить автоматическую буферизацию с помощью

local $| = 1;

Редактировать: я как-то ударил! вместо | в первый раз ... исправлено. Понятия не имею, как это произошло, они на противоположных сторонах клавиатуры.

8 голосов
/ 11 марта 2009

Попробуйте "Aborting. \ N"

Это похоже на проблему буферизации.

3 голосов
/ 12 марта 2009

Говоря о правильном использовании print, вы немного усложняете себя.

Интерполируйте ваши переменные вместо объединения строк вместе. Используйте один оператор печати со списком строк для печати вместо нескольких строк.

Вот один из способов:

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;
}

() на ложной стороне троичного оператора представляет собой пустой список, который исчезнет, ​​когда аргументы объединения сгладятся. Если бы я использовал и пустую строку (''), каждый несоответствующий критерий привел бы к дополнительной пустой строке в результатах.

Вы также можете добавить собственную новую строку для каждого элемента, а затем пропустить объединение, если считаете, что это более читабельно:

    print $fh  
        "Partial match found.\n",
        $matched_uid   ? "UID #: $arguid exists.\n" : '',
        ...
2 голосов
/ 11 марта 2009

Вам нужно добавить трейлинг \ n к последнему printf. В противном случае вывод не будет сброшен на консоль.

0 голосов
/ 11 марта 2009

Либо Дэвид Норман прав, либо проблема в другом. Я просто набрал код внутри блока if в интерпретаторе perl, и он напечатал «Aborting». как и ожидалось. (У меня это работало даже без завершающего символа новой строки.)

...