如果数据开头有 % 百分比符号,如何在两个字之间移动数据?

如果数据开头有 % 百分比符号,如何在两个字之间移动数据?

我有一个日志文件,看起来像这样:

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-RTP-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-Control-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#
 policy-map AutoQoS-Police-CiscoPhone
SWEs-elmPCI-A-01(config-pmap)#

现在我必须查找%包含哈希的行之间以符号开头的所有行#,并将其放入另一个错误日志文件中。

如果您考虑上述情况,那么这应该进入错误日志文件。

   SWEs-elmPCI-A-01(config)#
     class AutoQoS-VoIP-RTP-Trust
                                   ^
    % Invalid input detected at '^' marker.

    SWEs-elmPCI-A-01(config)#
     class AutoQoS-VoIP-Control-Trust
                                   ^
    % Invalid input detected at '^' marker.

    SWEs-elmPCI-A-01(config)#

答案1

不确定这是否是您想要的,但是:

#!/bin/bash

awk '
BEGIN {
    err=0
}
/^SWE.*#$/ {
    if (err) {
        printf "%s\n%s", txt, $0
        txt=""
        err=0
    } else {
        txt=$0
    }
    next
}
/^% Invalid/ {
    err=1
    txt=txt "\n" $0
    next
}
{
    txt=txt "\n" $0
}
END {
    print ""
}
' "$1"

结果:

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-RTP-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-Control-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#

作为替代方案,我的想法是使用额外的行进行分组:

awk '
BEGIN {
    i = 0
    sep="------------------------------------------------"
}
/^% Invalid/ {
    printf "%s %3d\n%s\n%s\n%s\n",
    sep, ++i, txt, $0, sep
    txt=""
    next
}
/^SWE.*#$/ {

    txt=$0
    next
}
txt != "" {
    txt=txt "\n" $0
}
' "$1"

结果:

------------------------------------------------   1
SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-RTP-Trust
                               ^
% Invalid input detected at '^' marker.
------------------------------------------------
------------------------------------------------   2
SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-Control-Trust
                               ^
% Invalid input detected at '^' marker.
------------------------------------------------

答案2

也许是这样的:

sed 'H;/#$/!d;s/^/\
/;x;/\n%/!d;s/.//;x;s/.*//;x'

由于您需要错误之前和错误之后的提示,因此该提示包括两者,但不包括在一个错误之后和下一个错误之前都会显示的提示,以匹配示例输出。

如果我们包含两个提示,无论错误是否相互跟随,都会简单得多:

sed 'H;/#$/!d;x;/\n%/!d'

如果您只想要错误之前的提示,那也会简单得多:

sed '/#$/!{H;d;}
     x;/\n%/!d'

也许解释这些的最好方法就是翻译成更详细的语言,比如perl.在 中sed,保持空间就像一个用空行初始化的静态变量,而模式空间是一个sed依次分配给每一行输入的变量。就像是:

$hold_space = "\n";
LINE: while ($pattern_space = <>) {

  <sed commands go here>

  print $pattern_space; # unless -n option is passed
}

H命令翻译为:

$hold_space .= $pattern_space;

d命令翻译为:

next LINE;

即停止执行命令,丢弃模式空间并从下一行输入重新开始。

x交换模式和保持空间:

($pattern_space, $hold_space) = ($hold_space, $pattern_space);

所以最后一个sed命令翻译为:

$hold_space = "\n";
LINE: while ($pattern_space = <>) {

  if (! ($pattern_space =~ /#$/)) { # anything other than a prompt
    $hold_space .= $pattern_space;
    next LINE;
  }

  ($pattern_space, $hold_space) = ($hold_space, $pattern_space);

  if (! ($pattern_space =~ /\n%/)) {
    next LINE;
  }

  print $pattern_space;
}

可以用更易读的方式重写为:

LINE: while ($pattern_space = <>) {

  if ($pattern_space =~ /#$/)) {
    if ($hold_space =~ /\n%/)) {
      print $hold_space;
    }
    $hold_space = $pattern_space;
  } else {
    $hold_space .= $pattern_space;
  }
}

重命名$pattern_space$line$hold_spaceto $current_block,它会变得更加清晰。

相关内容