【问题标题】:Perl split stops at first linePerl split 在第一行停止
【发布时间】:2014-12-04 12:16:26
【问题描述】:

编辑:重写示例以使其更清晰

我将数据放入一个名为 RTR-shpolicymap_751257S0_126.xxx.xxx.xxx_OUTPUT 的文件中:

751257S0;126.xxx;FastEthernet0;up;up;not set;not set;;
751257S0;126.xxx;BRI0;down;down;not set;not set;;
751257S0;126.xxx;BRI0:1;down;down;not set;not set;;
751257S0;126.xxx;BRI0:2;down;down;not set;not set;;
751257S0;126.xxx;ATM0;up;up;not set;not set;;
751257S0;126.xxx;ATM0.835;up;up;not set;not set;;

一个perl脚本执行一个到路由器的SSH连接,当连接建立时,它调用函数executeCommands 这里描述了这个功能:

sub executeCommands {
    open(SSHCONFIG, "/tech/restools/scripts/mynet/RTR-ssh.conf");
    while (<SSHCONFIG>) {
        @ligne = split(/;/, $_ );
        $listop = $ligne[0];
        $listcmd = $ligne[1];
        $fileprefix = $ligne[2];
        $parsername = $ligne[3];
        $parsername =~ s/\s+\z// ;
        @cmd = split(/,/, $listcmd);

        #Si l'operateur passe en parametre match l'operateur dans le fichier de config - execution des commandes
        if ($listop =~ /$operateur/) {
            for ($index = 0; $index <= $#cmd; $index++) {
                $command = $cmd[$index];
                &changeCommand(\$command);
                &sendCommand($command, $fileprefix);
            }
        }
        else {
            next;
        }

配置文件包含以下内容:

OBS,9 Cegetel,Altitude;sh policy-map $policyinterface;RTR-shpolicymap;RTR-parser9.pl

现在,我遇到了函数 changeCommand

的问题
sub changeCommand {
    my $arg1 = $_[0];
    if ($$arg1=~/^(.*)(\$policyinterface)(.*)/) {
        print "recherche de l'interface contenant la policy voice correspondante... \n" ;
        $fichier_parser1OUTPUT = `find $WORKINGDIR -type f -name RTR-shipint_\"*$codesite*$ip*OUTPUT\"` ;
        @table_fichier_parser1OUTPUT = split(/\n/,$fichier_parser1OUTPUT);
        for ($index4 = 0 ; $index4 <= $#table_fichier_parser1OUTPUT ; $index4++) {
            $fichierNeeded = $table_fichier_parser1OUTPUT[$index4];
            open(DATA,$fichierNeeded) || die ("Erreur d'ouverture de $fichierNeeded\n");
            print "file $fichierNeeded have been opened \n";
            while (my $lineData=<DATA>) {
                print "i am printing this line $lineData \n";
                my @lineSplitter = split(/;/, $lineData );
                print "3e arg est <<$lineSplitter[2]>>\n";
            }
        $command = "sh policy-map int " . $interfaceNeeded ;
        }
    }
}

问题就在那里,这就是我执行脚本时发生的情况:

recherche de l'interface contenant la policy voice correspondante...
file /tech/restools/tmp/mynet/RTR-working-dir/RTR-shipint_751257S0_126.108.2.250_OUTPUT have been opened
i am printing this line 751257S0;126.108.2.250;FastEthernet0;up;up;not set;not set;;
3e arg est <<FastEthernet0>>

我的错误在哪里?是因为我已经在之前的函数中使用了 $_ 吗?

单独测试一个类似的脚本正在工作......

#!/usr/bin/perl
use strict ;

my $codesite="751257S0" ;
my $ip = "126.xxx.xxx.xxx" ;
my $WORKINGDIR="/tech/restools/tmp/mynet/RTR-working-dir";

my $fichier_parser1OUTPUT = `find $WORKINGDIR -type f -name RTR-shipint_\"*$codesite*$ip*OUTPUT\"` ;
my @table_fichier_parser1OUTPUT = split(/\n/,$fichier_parser1OUTPUT);
for (my $index4 = 0 ; $index4 <= $#table_fichier_parser1OUTPUT ; $index4++) {
        my $fichierNeeded = $table_fichier_parser1OUTPUT[$index4];
        open(DATA,$fichierNeeded) || die ("Erreur d'ouverture de $fichierNeeded\n");
        print "file $fichierNeeded have been opened \n";
        while (my $lineData=<DATA>) {
                print "i am printing this line $lineData \n";
                my @lineSplitter = split(/;/, $lineData );
                print "3e arg est <<$lineSplitter[2]>>\n";
                }
        }

打印

i am printing this line 751257S0;126.108.2.250;FastEthernet0;up;up;not set;not set;;

3e arg est <<FastEthernet0>>
i am printing this line 751257S0;126.108.2.250;BRI0;down;down;not set;not set;;

3e arg est <<BRI0>>
i am printing this line 751257S0;126.108.2.250;BRI0:1;down;down;not set;not set;;

3e arg est <<BRI0:1>>
...

【问题讨论】:

  • 是的,添加打印标量显示“1”
  • 文件是否有 Windows 行结尾?
  • split 仍然会产生几行,因为 Windows 在其行尾有 \n
  • 请阅读如何创建 MCVE (Minimal, Complete, Verifiable Example) 或 SSCCE (Short, Self-Contained, Correct Example) — 两个名称和链接用于相同的基本思想。前三行与您的问题无关;您需要设置文件名,然后打开并使用它。您是否在split 之前打印了$_?您是否在脚本的前面将$/ 设置为奇数,或者它是否未定义(通过local $/;)以便整个文件被吞食?您是否打印了所有拆分字段?这些是基本的调试技术。
  • @AKHolland:Windows 行尾仍包含换行符,因此行被正确分隔。问题来自chomp,它删除了尾随的换行符,但保留了 CR。

标签: perl file split


【解决方案1】:

鉴于文件fichier.1 中的问题数据,以下代码可以产生您所看到的效果:

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

local $/;
my $fichierNeeded = "fichier.1";
open(DATA,$fichierNeeded) || die ("Erreur d'ouverture de $fichierNeeded\n");
print "Fichier $fichierNeeded est ouvert\n";
while (<DATA>) {
    print "Ligne: $_";
    my @lineSplitter = split(/;/, $_ );
    print "3rd arg is <<$lineSplitter[2]>>\n";
}

这个输出是:

Fichier fichier.1 est ouvert
Ligne: 751257S0;126.xxx;FastEthernet0;up;up;not set;not set;;
751257S0;126.xxx;BRI0;down;down;not set;not set;;
751257S0;126.xxx;BRI0:1;down;down;not set;not set;;
751257S0;126.xxx;BRI0:2;down;down;not set;not set;;
751257S0;126.xxx;ATM0;up;up;not set;not set;;
751257S0;126.xxx;ATM0.835;up;up;not set;not set;;
3rd arg is <<FastEthernet0>>

如果省略local $/;,则输出为:

Fichier fichier.1 est ouvert
Ligne: 751257S0;126.xxx;FastEthernet0;up;up;not set;not set;;
3rd arg is <<FastEthernet0>>
Ligne: 751257S0;126.xxx;BRI0;down;down;not set;not set;;
3rd arg is <<BRI0>>
Ligne: 751257S0;126.xxx;BRI0:1;down;down;not set;not set;;
3rd arg is <<BRI0:1>>
Ligne: 751257S0;126.xxx;BRI0:2;down;down;not set;not set;;
3rd arg is <<BRI0:2>>
Ligne: 751257S0;126.xxx;ATM0;up;up;not set;not set;;
3rd arg is <<ATM0>>
Ligne: 751257S0;126.xxx;ATM0.835;up;up;not set;not set;;
3rd arg is <<ATM0.835>>

由于您没有给我们可用的代码片段(循环甚至是不完整的),并且您的代码不必要地使我们在目录等上运行find 命令,因此我们无法很好地重现您的环境。

正如我在评论中指出的,您需要学习如何创建 MCVE (Minimal, Complete, Verifiable Example) 或 SSCCE (Short, Self-Contained, Correct Example)。这是相同基本思想的两个名称(和两个描述)。我提供的代码接近于 MCVE 或 SSCCE(除非不清楚它是否重现了您的问题)。

还要注意一些基本的调试技术。打印出您刚刚读取的数据是发现问题的最基本方法。在第一个示例输出中,整个文件立即被吞入内存。如果$/ 的设置从您的代码中隐藏(有人在您调用的子程序中粗心),这可能是无价的。我还划定了匹配的字段(将它们括在双尖括号中),以便我可以更轻松地查看数据中是否有奇怪的字符。如果您不确定发生了什么,您应该做的第一件事是添加一些打印语句来打印您正在处理的内容。

【讨论】:

  • 这段代码是一个非常大的脚本的一部分,bash 用 args 调用 perl,尝试通过 SSH 连接到设备,写下文件命令,如“sh ip int brief”......当我' m 添加“local $/”语句,它会打印您期望的内容。这是什么意思 ?我已经在上面的“if”语句中使用了“$_”,就在这段代码之前。
  • 是不是表示“while () 将文件读取为一行而不是多行?
  • 这个问题已经修改了很多......一个假设是while (&lt;DATA&gt;) 命令会将文件读取为一行而不是多行。另一个是该文件只有一行,尽管您另有想法。显示的代码没有使用拆分名称,那么您为什么要关心它呢?如果循环内有函数调用,那么可能该函数正在使用&lt;DATA&gt; 句柄,这会导致循环完成。考虑更广泛地使用myuse strict; use warnings; 很好!使用词法文件句柄:open my $fh, '&lt;', $fichier or die.
【解决方案2】:

从乔纳森的回答开始

这是来自perldoc perlvar 的相关部分,讨论了您的程序中可能发生的情况

在大多数情况下,您希望 在更改它们之前本地化这些变量 [ 像 $/ ],因为如果你不这样做, 更改可能会影响依赖于默认值的其他模块 您已更改的特殊变量。这是正确的之一 一次读取整个文件的方法:

       open my $fh, "<", "foo" or die $!;
       local $/; # enable localized slurp mode
       my $content = <$fh>;
       close $fh;

但是下面的代码很糟糕:

       open my $fh, "<", "foo" or die $!;
       undef $/; # enable slurp mode
       my $content = <$fh>;
       close $fh;

由于某个其他模块,可能想要从某个文件中读取数据 默认的“行模式”,所以如果我们刚刚呈现的代码已经 执行后,$/ 的全局值现在已更改为任何其他代码 在同一个 Perl 解释器中运行。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2016-07-28
    • 2020-11-09
    • 1970-01-01
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多