Почему мой процесс jzip зависает, когда я вызываю его в системе Perl? - PullRequest
1 голос
/ 08 января 2010

Я определенно новичок в Perl, и, пожалуйста, прости меня, если это покажется тебе глупым вопросом.

Я пытаюсь распаковать несколько файлов .cab с помощью jzip в Perl (ActivePerl, jzip, Windows XP):

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;
use IO::File;

use v5.10;

my $prefix = 'myfileprefix';
my $dir = '.';

File::Find::find(
    sub {
        my $file = $_;
        return if -d $file;          
        return if $file !~ /^$prefix(.*)\.cab$/;  
  my $cmd = 'jzip -eo '.$file;
  system($cmd);
    }, $dir
);

Код распаковывает первые .cab файлы в папке и зависает (без ошибок). Он висит там, пока я не нажму Ctrl + c, чтобы остановиться. Кто-нибудь знает, в чем проблема?

РЕДАКТИРОВАТЬ: я использовал processxp для проверки процессов, и я обнаружил, что запущено правильное количество процессов jzip (на количество cab-файлов находится в исходной папке). Однако только один из них запускается под cmd.exe => perl, и ни один из этих процессов не завершается после запуска. Мне кажется, мне нужно закрыть процесс и выполнить его один за другим, что я понятия не имею, как это сделать в Perl. Есть указатели?

РЕДАКТИРОВАТЬ: я также пытался заменить jzip на блокнот, оказывается, он открывает блокнот с одним файлом за раз (в последовательном порядке), и только если я вручную закрываю блокнот, запускается другой экземпляр. Это обычное поведение в ActivePerl?

РЕДАКТИРОВАТЬ: Я наконец решил, и я до сих пор не совсем уверен, почему. Что я сделал, так это удалил библиотеку XML из скрипта, что не должно относиться к делу. Извините, что вначале я целенаправленно удалил «использовать XML :: DOM», так как думал, что это совершенно не относится к этой проблеме. OLD: использовать строгое; используйте предупреждения;

use File::Find;
use IO::File;
use File::Copy;
use XML::DOM; 

use DBI;
use v5.10;

NEW:

#!/usr/bin/perl
use strict;
use warnings;

use File::Find;
use IO::File;
use File::Copy;

use DBI;
use v5.10;

my $prefix = 'myfileprefix';
my $dir = '.';

# retrieve xml file within given folder
File::Find::find(
    sub {
        my $file = $_;
        return if -d $file;             
        return if $file !~ /^$prefix(.*)\.cab$/;
        say $file;
        #say $file or die $!;
        my $cmd = 'jzip -eo '.$file;
        say $cmd;
        system($cmd);       
    }, $dir
);

Это, однако, создает еще одну проблему: когда извлеченный файл уже существует, скрипт снова зависнет. Я очень подозреваю, что это проблема jzip, и альтернативой решения этой проблемы является простая замена jzip на extract, как @ ghostdog74 указал ниже.

Ответы [ 5 ]

1 голос
/ 08 января 2010

Прежде всего, если вы используете команды через вызов system (), вы всегда должны перенаправлять их вывод / ошибку в журнал или, по крайней мере, на процесс в вашей программе.

В этом конкретном случае, если вы делаетечто у вас будет журнал того, что делает каждая отдельная команда, и вы увидите, если / когда какая-либо из них застрянет.

Во-вторых, просто общий совет, это хорошая идея, чтобы всегда использовать нативные библиотеки Perl- в этом случае, конечно, это может быть невозможно (у меня нет такого опыта работы с Windows Perl, поэтому не знаю, есть ли в Perl модуль jzip, но ищите CPAN).

ОБНОВЛЕНИЕ Не нашел собственного экстрактора CAB для Perl, но нашел замену jzip, которая могла бы работать лучше - стоит попробовать.http://www.cabextract.org.uk/ - есть версия для DOS, которая, будем надеяться, будет работать на Windows

0 голосов
/ 08 января 2010

Хотя никто не упомянул об этом явно, system блокируется до завершения процесса. Как отмечали люди, реальная проблема - выяснить, почему процесс не завершается. Форкинг или любое другое распараллеливание не поможет, потому что у вас останется много зависших процессов.

Пока вы не сможете выяснить проблему, начните с малого. Сделайте самый маленький Perl-скрипт, который демонстрирует проблему:

#!perl
system( '/path/to/jzip',  '-eo', 'literal_file_name' ); # full path, list syntax!
print "I finished!\n";

Теперь дело в том, чтобы выяснить, почему он зависает, а иногда это означает разные решения для разных внешних программ. Иногда вам нужно закрыть STDIN перед запуском внешнего процесса или он сидит там, ожидая его закрытия, иногда вы делаете что-то другое.

Вместо system вы также можете попробовать такие вещи, как IPC :: System :: Simple , который обрабатывает множество специфичных для платформы деталей, или модули, подобные IPC: : Запустите или IPC :: Open3 .

Иногда это просто отстой, и эта ситуация одна из таких.

0 голосов
/ 08 января 2010

вот альтернатива, используя extract.exe, который вы можете скачать здесь или здесь

use File::Find;
use IO::File;    
use v5.10;    
my $prefix = 'myfileprefix';
my $dir = '.';    
File::Find::find({wanted => \&wanted}, '.');
exit;
sub wanted {
    my $destination = q(c:\test\temp);
    if ( -f $_ && $_=~/^$prefix(.*)\.cab$/ ) {
         $filename = "$File::Find::name";
         $path = "$File::Find::dir";
         $cmd = "extract /Y $path\\$filename /E /L $destination";
         print $cmd."\n";
         system($cmd);
    }
} $dir;
0 голосов
/ 08 января 2010

Что происходит, когда вы запускаете команду jzip из окна dos?Это работает правильно?Что произойдет, если вы добавите символ конца строки (\ n) к команде в сценарии?Это предотвращает зависание?

0 голосов
/ 08 января 2010

Исходя из ваших правок, это то, что я предлагаю:

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;
use IO::File;

use v5.10;

my $prefix = 'myfileprefix';
my $dir = '.';

my @commands;

File::Find::find(
    sub {
        my $file = $_;
        return if -d $file;             
        return if $file !~ /^$prefix(.*)\.cab$/;        
        my $cmd = "jzip -eo $File::Find::name";
        push @commands, $cmd;
    }, $dir
);


#asynchronously kick off jzips
my $fresult;
for @commands
 {
    $fresult = fork();
    if($fresult == 0) #child
    {
     `$_`;
    }
    elsif(! defined($fresult))
    {
       die("Fork failed");
    }
    else
    {
       #no-op, just keep moving
    }

 }

edit: добавлена ​​асинхронность. edit2: исправлена ​​проблема с областью действия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...