代码之家  ›  专栏  ›  技术社区  ›  Kev

在win32上捕获尚未刷新的命令行输出

  •  1
  • Kev  · 技术社区  · 14 年前

    (上下文:我试图从Perl CGI脚本监视一个长时间运行的进程。它备份一个mssql数据库,然后7-zips。到目前为止,备份部分(使用 WITH STATS=1 )输出到一个文件,我可以让浏览器查看它,每隔几秒钟刷新一次,它就可以工作。)

    我试图使用7zip的命令行实用程序,但将进度条捕获到一个文件中。不幸的是,与sql备份不同的是,每次完成另一个百分比时,它都会输出另一行, 7zip在输出新的进度数据之前倒带其输出 ,所以如果您只是在命令行上正常使用它,它看起来会更好。这很不幸的原因是正常的重定向使用 > , 1> 2> 只创建一个空白文件,并且没有任何输出出现在其中,除了 > ,在作业完成之前没有输出,这对于进度条不是很有用。

    如何捕获这种输出,或者将%中的每一个更改以某种方式附加到日志文件中(这样我就可以使用现有的日志文件监视方法),只需使用命令行技巧(不使用perl),或者在调用 system() ?

    3 回复  |  直到 14 年前
        1
  •  1
  •   Sinan Ünür    14 年前

    如果需要一次捕获所有输出,则这是所需的代码:

    $var=`echo cmd`;
    

    如果要逐行读取输出,则需要以下代码:

    #! perl -slw
    use strict;
    use threads qw[ yield async ];
    use threads::shared;
    
    my( $cmd, $file ) = @ARGV;
    my $done : shared = 0;
    my @lines : shared;
    
    async {
        my $pid = open my $CMD, "$cmd |" or die "$cmd : $!";
        open my $fh, '>', $file or die "$file : $!";
        while( <$CMD> ) {
            chomp;
            print $fh $_;         ## output to the file
            push @lines, $_;    ## and push it to a shared array
        }
        $done = 1;
    }->detach;
    
    my $n = 0;
    while( !$done ) {
        if( @lines ) {            ## lines to be processed
            print pop @lines;   ## process them
        }
        else {
            ## Else nothing to do but wait.
            yield;
        }
    }
    

    另一个选项是使用windows创建进程。我知道windows c/c++创建过程将允许您重定向所有stdout。Perl可以访问这个相同的API调用:请参见 Win32::Process .

        2
  •  0
  •   Sinan Ünür    14 年前

    你可以试着打开一个 pipe 读取7zip的输出。

        3
  •  0
  •   Kev    14 年前

    这并不能回答如何捕获被重写的输出,但这是一种有用的方法,我最终使用了它。

    对于恢复:

    1. 使用 7za l 列出zip文件中的文件及其大小
    2. 7za e 使用 open my $command
    3. 跟踪每个文件 -s $filename 并与列表进行比较
    4. 当所有输出文件都是完整大小时,就完成了

    备份:

    1. 在某处创建一个唯一的目录
    2. 7za a -w
    3. 找到 .tmp 目录中的文件
    4. 跟踪它的大小
    5. TMP 文件不再存在,您完成了

    对于恢复,您可以获得足够的数据来显示完成的百分比,但是对于备份,您只能显示到目前为止的文件总大小,但是如果使用类似的数据来获取guestimate,则可以与历史比率进行比较。不过,现在的反馈比以前多了(没有)。