当我用Perl的系统调用它时,为什么我的jzip进程会挂起?

时间:2010-01-07 23:30:11

标签: perl system

我绝对是Perl的新手,请原谅我,如果这对你来说似乎是一个愚蠢的问题。

我试图在Perl(ActivePerl,jzip,Windows XP)中使用jzip解压缩一堆 .cab 文件:

#!/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”,因为我认为这与此问题完全无关。 旧:     用严格;     使用警告;

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,就像下面指出的@ ghostdog74一样。

5 个答案:

答案 0 :(得分:1)

首先,如果您通过system()调用使用命令,则应始终将其输出/错误重定向到日志或至少在程序中处理。

在这种特殊情况下,如果你这样做,你就会记录每一个命令正在做什么,并会看到是否/何时它们被卡住了。

其次,只是一般提示,总是使用本机Perl库是个好主意 - 在这种情况下,当然可能是不可能的(我不熟悉Windows Perl,所以没有线索,如果有一个jzip模块Perl,但搜索CPAN)。

UPDATE :没有找到Perl原生CAB提取器,但找到了一个可能更好的jzip替换 - 值得一试。 http://www.cabextract.org.uk/ - 有一个DOS版本可以在Windows上运行

答案 1 :(得分:0)

根据您的编辑,我建议这样做:

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

 }

编辑:添加了asynch。 edit2:固定范围问题。

答案 2 :(得分:0)

从dos窗口运行jzip命令会发生什么?它运作正常吗?如果在脚本中的命令中添加行尾字符(\ n),会发生什么?这会阻止挂起吗?

答案 3 :(得分:0)

这是另一种方法,使用extract.exe,您可以下载herehere

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;

答案 4 :(得分:0)

虽然没有人明确提到过,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::RunIPC::Open3等模块。

有时它很糟糕,这种情况就是其中之一。