【问题标题】:transpose variable amount of rows with variable amount of columns in them to <pattern> followed by all the rows till next <pattern>将可变数量的行与可变数量的列转置到 <pattern>,然后是所有行,直到下一个 <pattern>
【发布时间】:2019-08-10 21:38:59
【问题描述】:

我有以下与多接口(数十个)网络设备相关的输入(注意带有# 的行仅用于澄清,数据中不存在):

eth<number1> 
# eth as pattern is fine, running number will be dealt with
parameter1 parameter2 parameter3...parameterN 
#ellipsis means and so on and is not literal
parameter21 parameter22
parameter31 parameter32 parameter33 parameter34
parameter41
eth<number2>
parameter1 parameter2
parameter21
.
.
.
.
parameterN1 parameterN2  
# again, vertical ellipsis is not literal and means simply that rows 
# with parameters can go on and on, it is not known in advance for 
# how long
eth<number3>
parameter1 parameter2
eth<number4>
parameter1 parameter2
parameter21

所需的输出应如下所示:

eth<number1> parameter1 parameter2 parameterN parameter21 parameter22 parameter31 parameter32 parameter33 parameter34 parameter41 
# all in one line, with as many columns as there are parameters for 
# the given interface.
eth<number2> parameter1 parameter2....parameterNM
eth<number3> parameter1 parameter2
eth<number4> parameter1 parameter2 parameter21

任何想法如何使用awk 或sed 来完成它?当然,欢迎任何澄清问题。

【问题讨论】:

  • 删除您示例中的所有.s,以便我们可以测试潜在解决方案并添加您迄今为止尝试过的内容。如果不清楚,请参阅How to Ask。

标签: perl awk sed text-processing


【解决方案1】:

这在 Perl 中应该很容易做到。 eth 行很容易匹配,我们只想将它们之间的所有行合并为一行。

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

my $collected;
while (my $line = <DATA>){
  next if $line =~ /^#/;
  if($line =~ /^eth/) {
    # new block of lines
    if ($collected) {
      print $collected, "\n";
      $collected = "";
    }
    chomp $line;
    $collected = $line;
  } else {
    # Append to collected lines
    chomp $line;
    $collected = "$collected $line";
  }
}
print $collected,"\n" if $collected;
__DATA__
eth<number1>
parameter1 parameter2 parameter3...parameterN
#ellipsis means and so on and is not literal
parameter21 parameter22
parameter31 parameter32 parameter33 parameter34
parameter41
eth<number2>
parameter1 parameter2
parameter21
parameterN1 parameterN2
eth<number3>
parameter1 parameter2
eth<number4>
parameter1 parameter2
parameter21

这将解析您的示例数据(忽略 cmets)并创建所需的输出。当然,这只是一个演示;你想open 数据所在的文件并读取它:

open my $fh, "<", "your.data" or die "Can't open file: $!\n";
...
while(my $line = <$fh>) { 
...

【讨论】:

  • 是的,它会做,而且很清楚如何做(会做意味着它足够好和通用,可以用实际输出来做)。 awk,在您看来,不够适合这种类型的任务?
  • 我确定使用awk 是可能,但对我来说,使用 Perl 编写它更容易。
【解决方案2】:

这可能对你有用(GNU sed):

sed -E '/^#/d;/^eth/!{H;$!d};x;s/\n/ /gp;x;h;d' file

共有三种情况:以# 开头的行、以`eth 开头的行和其他行。

如果当前行是注释,删除它。

如果当前行不是以eth 开头,则将其附加到保持空间 (HS) 并删除它,除非它是最后一行。

否则,当前行以eth 开头或者是最后一行,因此切换到 HS,如果其中包含任何换行符,请将它们替换为空格并打印结果。切换回模式空间并将 HS 替换为当前行并删除当前行,除非它是文件的最后一行,在这种情况下打印它。

【讨论】:

  • 这很优雅!
  • 也许(而且很可能)我不够清楚,对此我很抱歉,但 不是字面意思,因为在输入中找不到 <...> -- 我试图表示给定接口的运行号。在现实中,它看起来像: eth 1-43 ;伦理 1-44;伦理 2-36; eth 2-37 等等,原则上这些行下面的参数 可以很好地包含相同的数字模式。
  • @protong -- 好的,我仍在消化 sed 咒语(包括 HS 的概念),但是,非常明显的情况是最后一行(行)都被转置到最后一列最后一个 eth 条目,也打印为最后一行。因此,在示例输入中,参数 21 既作为包含 eth 的行的最后一列,也作为单独的行打印出来。你可以自己试试。
  • @potong,刚刚得到了一些空闲时间——它仍然会打印两次。示例输入具有足够的代表性。
猜你喜欢
  • 1970-01-01
  • 2013-09-23
  • 1970-01-01
  • 2019-09-05
  • 2013-06-21
  • 2019-12-05
  • 1970-01-01
  • 1970-01-01
  • 2018-01-27
相关资源
最近更新 更多