Perl替代正则表达式

时间:2012-01-20 23:41:58

标签: perl substitution

当我在Perl one liner上运行此命令时,它会获取正则表达式 - 这样也不错。

more tagcommands | perl -nle 'print /(\d{8}_\d{9})/' | sort 

12012011_000005769
12012011_000005772
12162011_000005792
12162011_000005792

但是当我在下面的命令调用上运行这个脚本时,它没有拿起 正则表达式。

#!/usr/bin/perl
use strict; 
my $switch="12012011_000005777";
open (FILE, "more /home/shortcasper/work/tagcommands|");
my @array_old = (<FILE>) ;
my @array_new = @array_old ;
foreach my $line(@array_new) {
        $line =~ s/\d{8}_\d{9}/$switch/g;
        print $line;
        sleep 1;
}

这是我提供给脚本的数据

/CASPERBOT/START URL=simplefile:///data/tag/squirrels/squirrels    /12012011_000005777N.dart.gz CASPER=SeqRashMessage
/CASPERBOT/ADDSERVER simplefile:///data/tag/squirrels/12012011_0000057770.dart.trans.gz
/CASPERRIP/newApp multistitch CASPER_BIN
/CASPER_BIN/START URLS=simplefile:///data/tag/squirrels    /12012011_000005777R.rash.gz?exitOnEOF=false;binaryfile:///data/tag/squirrels/12162011_000005792D.binaryBlob.gz?exitOnEOF=false;simplefile:///data/tag/squirrels/12012011_000005777E.bean.trans.gz?exitOnEOF=false EXTRACTORS=rash;island;rash BINARY=T

2 个答案:

答案 0 :(得分:4)

你应该研究你的单行,看它是如何运作的。首先检查perl -h以了解所使用的交换机:

-l[octal]         enable line ending processing, specifies line terminator
-n                assume "while (<>) { ... }" loop around program

第一个并不是完全不言自明的,但-l实际上每行chomp的行为是$\,然后将$/perl -nle 'print /(\d{8}_\d{9})/' 更改为换行符。所以,你的单行:

$\ = "\n";
while (<>) {
    chomp;
    print /(\d{8}_\d{9})/;
}

实际上这样做:

$ perl -MO=Deparse -nle 'print /(\d{8}_\d{9})/'
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    print /(\d{8}_\d{9})/;
}
-e syntax OK

一种非常简单的方法是使用Deparse命令:

use strict; 
my $switch="12012011_000005777";
open (FILE, "more /home/shortcasper/work/tagcommands|");
my @array_old = (<FILE>) ;
my @array_new = @array_old ;
foreach my $line(@array_new) {
        $line =~ s/\d{8}_\d{9}/$switch/g;
        print $line;
        sleep 1;
}

所以,这就是你将其转换为工作脚本的方式。

我不知道你是怎么做到的:

more

首先,为什么要从while(<FILE>)命令打开管道来读取文本文件?这就像叫一辆拖车去取你的出租车。只需打开文件即可。或者更好,不要。只需使用钻石操作符,就像你第一次做的那样。

您无需先将文件行复制到数组中,然后再使用该数组。 $line是一种简单的方法。

在你的单行中,你打印正则表达式。好吧,你打印正则表达式的返回值。在此脚本中,您打印sleep 1。我不确定你认为那会做同样的事情。

此处的正则表达式将删除所有数字集,并将其替换为脚本中的数字。没别了。

您可能也知道perl -we 'for (1 .. 10) { print "line $_\n"; sleep 1; }' 不符合您的想法。试试这个单行,例如:

STDOUT->autoflush(1);

正如您将注意到的,它只需等待10秒钟,然后立即打印所有内容。这是因为perl默认打印到标准输出缓冲区(在shell中!),并且该缓冲区在完全或刷新之前不打印(当perl执行结束时)。所以,这是一个感知问题。一切都像它应该的那样,你只是看不到它。

如果您绝对想在脚本中使用sleep语句,则可能需要autoflush,例如more

但是,你为什么这样做?难道你有时间阅读这些数字吗?如果是这样,请将perl ...... | more 语句放在单行的结尾上:

more

这会将输出传输到-w命令,因此您可以按自己的步调阅读。现在,为你的单行:

始终也使用perl -wnle 'print for /(\d{8}_\d{9})/g' ,除非你特别想避免收到警告(基本上你永远不应该这样做)。

你的单线只会打印第一场比赛。如果要在新行上打印所有匹配项:

perl -wnle 'print "@a" if @a = /(\d{8}_\d{9})/g'

如果要打印所有匹配项,但保持同一行中的匹配项:

{{1}}

嗯,这应该涵盖它。

答案 1 :(得分:1)

你的open电话可能会失败(如果程序的其余部分依赖它,你应该总是检查open的结果以确保它成功)但我相信你的问题很复杂通过从more命令打开管道而不是简单地打开文件本身。将打开更改为

open FILE, "/home/shortcasper/work/tagcommands" or die $!;
事情应该有所改善。