データの先頭に%パーセント記号がある場合は、2つの単語の間でデータを移動できますか?

データの先頭に%パーセント記号がある場合は、2つの単語の間でデータを移動できますか?

次のログファイルがあります。

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'

エラーの前後にプロンプ​​トが必要なため、このプロンプトには両方が含まれますが、出力例と一致するようにしたエラーの後と次のエラーの前に表示されるプロンプトは含まれません。

エラーが互いにつながるかどうかにかかわらず、2つのヒントを含めると、はるかに簡単になります。

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名前を to$line$hold_spaceto に変更すると、$current_blockより明確になります。

関連情報