简体   繁体   English

Perl怪异的Chomp和换行符

[英]Perl weird chomp and newline

I'm having weird things when extracting line from file. 从文件中提取行时出现奇怪的事情。

Lines are coming from SSH commands sent on a router and saved into a file. 线路来自路由器发送的SSH命令,并保存到文件中。 They are looking like : saved_commands 它们看起来像: saved_commands

    FastEthernet0 is up, line protocol is up
    Helper address is not set
    FastEthernet1 is up, line protocol is up
    Helper address is not set
    FastEthernet2 is up, line protocol is down
    Helper address is not set

So, in my PERL script, when i'm reading this file, I make this : 因此,在我的PERL脚本中,当我读取此文件时,将执行以下操作:

while (<LIRE>) {
    $ifname = "";
    $etat = "";
    $myip = "";
    if (/line protocol/) {
        @status = split(/,/, $_) ;
        @interface = split(/ /, $_);
        $ifname = $interface[0];
        for ($index = 0; $index <= $#status; $index++) {
            @etat_par_if = split(/ /, $status[$index]);
            $etat .= pop(@etat_par_if);
        }
    }
    if (/Helper|helper/) {
        @helper = split(/ /, $_) ;
        $myip = pop(@helper);
        if ($myip =~ /126/) {

        }
        else {
            $myip = "not set";
        }
    }
    if ($myip eq ""){
        $myip = "not set";
    }       
    if ($ifname ne ""){
    print "$ifname ; $etat ; $myip \n";
    }
}
close(LIRE);

The output should be : 输出应为:

FastEthernet0 ; upup ; not set
FastEthernet1 ; upup ; not set
FastEthernet2 ; updown ; not set

But unfortunately, the output is more like : 但是不幸的是,输出更像是:

FastEthernet0 ; upup
 ; not set
FastEthernet1 ; upup
 ; not set
FastEthernet2 ; updown
 ; not set

I guess there's a newline somewhere, probably at the end of each interface line. 我猜可能在每个界面行的末尾都有换行符。 But i tried several things, like chomp($_) , or even 但是我尝试了几件事,例如chomp($_) ,甚至

$_ =~ s/
//;

But things get weirder. 但是事情变得奇怪了。 EDIT : I tried other answers, having same issue. 编辑:我尝试了其他答案,有同样的问题。 Using Borodin's answer : 使用鲍罗丁的答案:

my ($etat, $ifname, $myip);

open(DATA,$fichier) || die ("Erreur d'ouverture de $fichier\n") ;
while (<DATA>) {

    if (/line protocol/) {
        $ifname = (split)[0];
        my @status    = split /,/;
        for (@status) {
          $etat .= (split)[-1];
        }
    }
    elsif (/helper/i) {
        my @helper = split;
        $myip = (split)[-1];
        $myip = 'not set' unless $myip =~ /\d/;
    }

    if ($ifname and $myip) {
      print "$ifname ; $etat ; $myip\n";
      $etat = $ifname = $myip = undef;
    }

}
close(DATA);

The output is like 输出就像

FastEthernet0 ; upup ; not set
Vlan1 ; downdowndowndowndowndownupupupdownupdownupdownupdownupdownupdownupdownupup ; 126.0.24.130
Loopback0 ; upup ; not set
Loopback1 ; upup ; not set
Tunnel100 ; upupupupupup ; not set
Dialer1 ; upup ; not set
Tunnel101 ; upup ; not set
Tunnel200 ; upup ; not set
Tunnel201 ; upup ; not set
Tunnel300 ; upup ; not set

We are getting closer to it, what happened to the others FastEthernet interfaces ? 我们越来越接近它,其他FastEthernet接口又发生了什么?

The problem is that you are processing a file from a Windows system that has CRLF at the end of each line instead of just LF (newline). 问题是您正在处理来自Windows系统的文件,该文件的每行末尾都有CRLF,而不仅仅是LF(换行符)。 chomp removes the newline, but the carriage-return remains and messes up your output. chomp删除了换行符,但是回车符仍然保留并且使您的输出混乱。 You can get around this by using s/\\s+\\z// instead of chomp . 您可以使用s/\\s+\\z//代替chomp

But you can avoid the problem with line terminators altogether by using split with a single space string (not a regex). 但是,您可以通过对单个空格字符串 (而不是正则表达式)使用split来完全避免行终止符的问题。 That is the default if you don't pass any parameters at all, and it splits on any combination of whitespace (which includes newlines and carriage-returns), ignoring any leading spaces. 如果您根本不传递任何参数,那么它将是默认值,它将在空白的任何组合(包括换行符和回车符)上分割,而忽略任何前导空格。

This program seems to do what you want. 该程序似乎可以满足您的要求。 It makes use of regular expressions instead of split to get straight to the correct part of the data without using temporary arrays. 它使用正则表达式而不是split来直接获取数据的正确部分,而无需使用临时数组。

use strict;
use warnings;

my $fichier = 'fichier.txt';

open my $lire, '<', $fichier or die "Erreur d'ouverture de $fichier: $!";

my ($ifname, $etat, $myip);

while (<$lire>) {

   if (/line protocol/) {

      if ($ifname) {
         printf "%s ; %s ; %s\n", $ifname, $etat, $myip // 'not set';
         $myip = undef;
      }

      ($ifname) = /(\S+)/;
      $etat = join '', /(\S+)\s*(?:,|\z)/g;
   }
   elsif (/helper.*\s([\d.]+)/i) {
      $myip = $1;
   }

}

if ($ifname) {
   printf "%s ; %s ; %s\n", $ifname, $etat, $myip // 'not set';
}

fichier.txt fichier.txt

FastEthernet0 is up, line protocol is up
Helper address is not set
FastEthernet1 is up, line protocol is up
Helper address is not set
FastEthernet2 is up, line protocol is down
Helper address is 126.0.24.130
FastEthernet3 is up, line protocol is down
FastEthernet4 is up, line protocol is down
Helper address is 126.0.24.128
FastEthernet5 is up, line protocol is down

output 输出

FastEthernet0 ; upup ; not set
FastEthernet1 ; upup ; not set
FastEthernet2 ; updown ; 126.0.24.130
FastEthernet3 ; updown ; not set
FastEthernet4 ; updown ; 126.0.24.128
FastEthernet5 ; updown ; not set

I am not getting anything weird in your code but you are not using chomp anywhere in the code. 我在您的代码中没有得到任何奇怪的东西,但是您在代码中的任何地方都没有使用chomp。

Just add chomp $_; 只需添加chomp $_; at the very start of your while loop. 在您的while循环开始时。

Try this Code: 试试这个代码:

while (<DATA>) {
    chomp;
    $ifname = "";
    $etat = "";
    $myip = "";
    if (/line protocol/) {
        @status = split(/,/, $_) ;
        @interface = split(/ /, $_);
        $ifname = $interface[0];
        for ($index = 0; $index <= $#status; $index++) {
            @etat_par_if = split(/ /, $status[$index]);
            #chomp @etat_par_if;
            $etat .= pop(@etat_par_if);
        }
    }
    if (/Helper|helper/) {
        @helper = split(/ /, $_) ;
        $myip = pop(@helper);
        if ($myip =~ /126/) {

        }
        else {
            $myip = "not set";
        }
    }
    if ($myip eq ""){
        $myip = "not set";
    }       
    if ($ifname ne ""){
    print "$ifname ; $etat ; $myip \n";
    }
}
close(DATA);


__DATA__
FastEthernet0 is up, line protocol is up
Helper address is not set
FastEthernet1 is up, line protocol is up
Helper address is not set
FastEthernet2 is up, line protocol is down
Helper address is not set

and this is the output: 这是输出:

FastEthernet0 ; upup ; not set 
FastEthernet1 ; upup ; not set 
FastEthernet2 ; updown ; not set 

Try this $etat =~ s/[\\n]+$//; 试试这个$ etat =〜s / [\\ n] + $ //; or if that fails $etat =~ s/[\\r\\n]+$//; 或如果失败$ etat =〜s / [\\ r \\ n] + $ //;

I suspect you have one of these as the end of your newlines in the file being read in. I also suspect a single chomp may not work if the line ends in \\r\\n. 我怀疑您在读入文件的换行符末尾有这些字符之一。我还怀疑如果该行以\\ r \\ n结尾,单行压缩可能无法正常工作。

Without knowing the actual input file exact details the below is a suggestion and is written based on the contents of the input file you have provided in your post. 不知道实际输入文件的确切详细信息,以下是建议,是根据您在帖子中提供的输入文件的内容编写的。

use strict;
use warnings;

open (my $file, '<', 'LIRE.txt') or die "unable to open file : $!\n";
while (<$file>) {
        chomp();
        if (/line protocol/){
                my ($ifname) = /^([A-Za-z0-9]+)\s/;
                my @status = map { /\s([A-Za-z]+)$/ } split(',');
                print "$ifname ; ", @status;
        } elsif (/[Hh]elper/){
                my $ip = /\s(\w+)$/;
                print " ; ", $ip =~ /126/ ? $ip : "not set", "\n";
        }
}
close($file);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM