perl脚本在文本文件中搜索特定字符串并将整行复制到新文件中?

时间:2009-04-09 04:40:58

标签: perl

我遇到的主要问题是我的脚本运行,打开文本文件,查找字符串,并将其复制到新文件,但有时它不会复制整个行。它在线路的不同点被切断。我相信我的正则表达式存在问题。

一行txt可能如下所示:

  

E03020039:无法将C:\ Documents and Settings \ rja07 \ Desktop \ DSMProduct \ project \ Database \ Schema \ Source \ MDB_data_type.dsm加载到\ DSM R17 \ projects \ Databases \ Schema \ Source \ MDB_data_type.dsm中。文本文件包含无效字符。

但是,当Perl脚本运行时,它有时只会复制到“文本文件”或“文本文件包含”字样,并且该行的最后部分被截断。我需要完整的一行。这就是我到目前为止所做的:

if ($error =~ /E03020039/)
{
    print $error;
    open (MF, '>>G:/perl/error.txt');
    print MF $error;
    $count ++;
    }   

对于扫描文件每一行的每个循环,这都在一个内部:

我试过了:

if ($error =~ /E03020039/&&/characters\s\.\n/)

但这对我没有任何帮助。

6 个答案:

答案 0 :(得分:8)

在我们等待您提供的信息brian d foy时,我们应该检查一些可能的事情。

为什么?

好吧,看看你发布的代码片段,至少在风格方面,你似乎使用了一些更传统的Perlism,而不是现代改进的Perlisms,而现代方式做事通常会让你的生活更轻松。

您使用的是Strictures吗?

use strict; 
use warnings; 

代码顶部的这两行可以帮助指出许多愚蠢的错误。

如果由于错误太多而无法在任何地方打开它们,您可以在范围内执行它们,即:

 blah;  #no strict or warnings

 {   # scope 

     use strict; 
     use warnings; 
     code(); # with strict and warnings

 }

 blah; # no strict or warnings

使用词汇文件句柄

裸露的文件句柄不整洁,因为它们是全球唯一的,这可能会有点混乱。

{  #scope

  open my $fh , '>' , 'bar.txt'; 
  print $fh "Hello\n";

}  # file cleaned up and closed by perl!

尽可能使用3-Arg

好:

open my $fh, '>', 'bar.txt'; 
open my $otherfh, '<', 'foo.txt'; 
open my $iofh , '-|' , 'ls', '-la' ; 

不推荐:

open my $fh, '>bar.txt'; 
open my $otherfh , '<foo.txt'; 
open my $iofh , 'ls -la |'; 

有关详细信息,请参阅perldoc -f open

检查Opens是否确实有效

一般情况下,如果因任何原因而开放死亡,默认行为是继续卡车运输,这可能有点奇怪。

有几种方法可以解决这个问题:

选项1:

 use Carp(); 
 open my $fh , '>', $filename  or Carp::croak("Oh no! cant open $filename , $! $@"); 

选项2:

 use autodie;
 open my $fh , '>', $filename;

至于第二个正则表达式

多数民众赞成可能没有按照你的想法去做。

 if ($error =~ /E03020039/&&/characters\s\.\n/)

基本相同
 if (  
         ( $error =~ /E03020039/ ) 
     &&  ( $_     =~ /characters\s\.\n/ ) 
 ) 

这可能不是你想要的。

我认为你的意思是:

 if (  
          ( $error =~ /E03020039/ ) 
      &&  ( $error =~ /characters\s\.\n/) 
 ) 

答案 1 :(得分:2)

我不认为你的正则表达式与此有任何关系。您是否至少在新文件中获得了所有正确的行,即使它们被截断了?

我认为您需要完成正常的调试步骤:

  • 您能告诉我们一个完整但极少的程序来演示错误吗?问题可能出在其他地方。

  • 什么是$ error?当你将它打印到标准输出时它是否具有所有的线?如果没有,请向后工作,直到找到文本丢失的位置。在可疑操作之前和之后打印其值,然后向后工作,直到找到问题为止。

  • 您确定所有文字都在一行上,或者文件中没有任何额外的奇怪字符?下一行读取的错误是什么?

  • 如果您将所有内容打印到新文件(即匹配所有行)会发生什么?所有文本是否都以新文件结尾?

  • 这些行是否总是在同一点被截断?

答案 2 :(得分:0)

如果使用匹配模式(//与m //相同),则〜=运算符不应修改错误字符串。

在正则表达式检查之前,您是否100%确信自己没有将其破坏?我会在比赛前贴上一条打印线,确保你准确地复制输入。

您是否100%确信自己没有遇到IO缓冲问题?通常perl文件IO是缓冲的,所以如果你期望通过tail -f看到日志文件的完整,最后一行,你可能会在程序退出之前失望。

有关如何为文件句柄启用自动刷新的一些选项,请参阅http://www.rocketaware.com/perl/perlfaq5/How_do_I_flush_unbuffer_a_fileha.htm

答案 3 :(得分:0)

如果只是为了完成工作 - 而不是学习如何在Perl中编程 - 那么使用'grep'来找到这些行。这也假设你在脚本中没有做任何其他事情。如果打算了解Perl,那么你会忽略这个建议并注意其他答案。

答案 4 :(得分:-1)

我看到一些事情立即脱颖而出:

  1. 您正在使用全局文件句柄,完成后不会关闭它。
  2. 您正在使用两个参数打开(这不会导致您的问题,但最好避免)。
  3. 你改变的正则表达式并没有像你认为的那样做任何事情。
  4. 对于1和2:

    # For loop around this:
    if ($error =~ /E03020039/) {
        print $error;
    
        open(my $mf, '>>', 'G:/perl/error.txt') 
            or die "Unable to open error file - $!\n";
    
        print $mf $error;
        $count ++;
    
        close $mf
            or die "Unable to close error file - $!\n";
    }
    

    通过使用词法句柄,您可以防止任何其他代码在未明确传递的情况下触摸您的句柄。通过关闭句柄,可以刷新句柄的缓冲区。通过检查打开和关闭句柄的错误,可以防止未捕获的错误导致数据丢失。

    您可能希望在for循环外移动打开和关闭:

    my $count = 0;
    open( my $mh, '>>', 'errorlog.log' ) or die "oops $!\n";
    for my $error ( <$log_h> ) {
    
        if ( $error =~ /E23323232323/ ) {
             print $mh $error;
             print $error;
             $count++;
        } 
    
    }
    close $mh or die "oops $!\n";
    

    您的代码正在重新打开同一个文件到全局文件句柄中。这可能很容易成为您所看到的问题的原因。它可能不是。错误的正确信息是否打印到STDOUT?

    关于问题3,$error =~ /E03020039/&&/characters\s\.\n/相当于:

    ($error =~ /E03020039/) && ($_ =~ /characters\s\.\n/)
    

    如果您启用了警告,则可能(可能)收到Use of uninitialized value in pattern match (m//)错误消息。这可能是令人惊讶的,但这可能是一个错误的线索。

    我相信你想要的东西:

    $ error =〜/ E03020039。*?characters \ s。$ /

    但是没有理由扩展比赛,因为你没有捕捉到比赛的任何部分。它对$error中的值或将写入文件的内容没有影响。

    除非您有特殊原因,否则请始终使用以下两个pragma启动您的perl程序:

    use strict;
    use warnings;
    

    即使你有充分的理由不使用它们,最好只在有限的范围内禁用这些pragma:

    use strict;
    use warnings;
    
    {    no warnings 'uninitialized';
         no strict 'vars';
         print "$foo\n";
    }
    

答案 5 :(得分:-1)

你的正则表达没问题。

还有其他两个问题:

  1. 你的外部foreach循环有一些 错误。
  2. 使用open (MF, '>>G:/perl/error.txt');附加到error.txt。因此,如果此脚本的多个实例并行运行,如果所有这些实例都尝试同时写入该文件,则可能会导致输出出现问题。
  3. 或者你可以使用这个简单的Perl单线程,它可以达到你想要的目的:

    perl -nle 'print if /E03020039/' inputFile.txt >> G:/perl/error.txt