複雑なDIFF法

複雑なDIFF法

空き状況とステータスが変更されていないことを確認するために、既存のボックスと新しいボックスの構成を比較しようとしています。

約1,000個のノードで作成されたファイルがありますが、各ノードには次の行があります(他の値を含む)。だから私の目標は、比較/違いスクリプトを実行するときに行の値を抽出したいことです。
最初の行の場合は、Ltm::Node:(中かっこの間の値) を指定するだけです。

Availability (keep value after :)
State (keep value after :)
Reason (keep value after :)
Monitor (keep value after : but if exists do not include (default node monitor)
Monitor Status (keep value after :)

--------------------------------------------------
Ltm::Node: Development/10.47.63.133 (10.47.63.133)
--------------------------------------------------
Status
  Availability   : available
  State          : enabled
  Reason         : Node address is available
  Monitor        : /Common/icmp (default node monitor)
  Monitor Status : up

ここに古いものがあります。

Ltm::Node: Common/splunk-hec1-p.mwg.com (::)
  Availability   : unavailable
  State          : enabled
  Reason         : No records returned
  Monitor        : /Common/icmp (default node monitor)
  Monitor Status : fqdn-up-no-address
Ltm::Node: Common/_auto_10.72.7.122 (10.72.7.122)
  Availability   : unknown
  State          : enabled
  Reason         : Node address does not have service checking enabled
  Monitor        : Common/none
  Monitor Status : unchecked
Ltm::Node: Common/_auto_10.72.12.148 (10.72.12.148)
  Availability   : unknown
  State          : enabled
  Reason         : Node address does not have service checking enabled
  Monitor        : Common/none
  Monitor Status : unchecked

違いを確認するためのいくつかの新しい内容があります(比較では名前の違いが表示されるため、小さくても難しい)。

Ltm::Node: splunk-hec1-p.mwg.com (::)
  Availability   : unavailable
  State          : enabled
  Reason         : No records returned
  Monitor        : /Common/icmp (default node monitor)
  Monitor Status : fqdn-up-no-address
Ltm::Node: _auto_10.72.7.122 (10.72.7.122)
  Availability   : unknown
  State          : enabled
  Reason         : Node address does not have service checking enabled
  Monitor        : Common/none
  Monitor Status : unchecked
Ltm::Node: _auto_10.72.12.148 (10.72.12.148)
  Availability   : unknown
  State          : enabled
  Reason         : Node address does not have service checking enabled
  Monitor        : Common/none
  Monitor Status : unchecked

なぜ?古いボックスから新しいボックスに移行すると、古いボックスは標準の命名規則に従わず、新しいボックスに従うため、名前Development / 10.47.63.133(または他の名前)はほとんど異なる場合があります。

前のボックスのすべての情報を.txtファイル(上記はファイルの一部です)にエクスポートし、新しいボックスでも同じことを行い、スクリプトを実行して比較して違いを見つけようとします。ミスマッチを見せることで迅速に攻撃し、解決策を見つけることができることを願っています。

誰かがAWKを提案しました。 diffを試しましたが、すべての行を表示できますが、ノードが1000を超え、時間がかかります。 Ltm::Node: (10.47.63.133) をインデックスとして使用して、古いバージョンと新しいバージョンを一致させます。次に、下のすべての項目を比較して、一致しない項目があるかどうかを確認します。

ご迷惑をおかけして申し訳ありませんが、この頭痛を説明する方法がわかりません

ベストアンサー1

このデータは、マルチレベルの連想配列として使用できます(またはPerl用語でHash-of-Hashes / HoHを参照)。ペルツカ、Perlデータ構造マニュアル)、最初のレベルのキーはノード名、2番目のレベルのキー(以下のスクリプトでは「サブキー」と呼ばれます)は関連フィールド名(可用性、状態、理由など)です。

たとえば、

#!/usr/bin/perl

use strict;

die "Usage $0 [oldfile] [newfile]\n" unless (@ARGV == 2) ;

# remember both filename args
my ($oldfile,$newfile) = @ARGV[0,1];

die "$oldfile is not readable or does not exist\n" unless -r $oldfile;
die "$newfile is not readable or does not exist\n" unless -r $newfile;

# Hash variables to hold old and new data
my (%old, %new);

# Hash reference variable pointing to the hash we want
# the main loop to populate at any given moment.
# Starts off pointing to %old, changes to %new after the
# first file reaches end-of-file.
# See https://perldoc.perl.org/perlreftut and
# https://perldoc.perl.org/perlref
my $hashref = \%old;

# variable to hold the name of the current node name as
# the records in the input files are read in.
my $node;

# read and parse input files
while(<>) {
  chomp;
  s/^\s*|\s*$//g; # strip leading and trailing whitespace
  s/\s+:\s+/ : /; # strip excess whitespace around first :

  if (/^Ltm::Node:.*\s+\((.*)\)/) {
    $node = $1;
    $hashref->{$node}{name} = $node;
  } elsif (/ : /) {
    my ($key, $val) = split / : /,$_, 2;
    $hashref->{$node}{$key} = $val
  } else {
    print STDERR "Unknown data '$_' on line $. of $ARGV\n";
  };

  if (eof) {
    close(ARGV);       # reset line counter
    $hashref = \%new;  # start populating %new instead of %old
  }
};

# compare the keys from both files
my @common_keys = ();
foreach my $k (keys %old) {
  if (exists($new{$k})) {
    push @common_keys, $k;
  } else {
    print "Node $k found in $oldfile but not in $newfile\n"
  };
};

foreach my $k (keys %new) {
  if (! exists($old{$k})) {
    print "Node $k found in $newfile but not in $oldfile\n";
  };
}

# The list of sub-keys we care about.
my @subkeys = ('Availability', 'State', 'Reason', 'Monitor',
               'Monitor Status');

# now compare sub-keys in each of the nodes
foreach my $k (@common_keys) {
  foreach my $sk (@subkeys) {
    if ($old{$k}{$sk} ne $new{$k}{$sk}) {
      printf "[%-15s %-14s] Old = \"%s\", new = \"%s\"\n", $k, $sk,
        $old{$k}{$sk}, $new{$k}{$sk};
    }
  }
}

たとえば、別の名前で保存してcompare.pl実行可能にし、chmod +x compare.pl次のように実行します。

$ ./compare.pl old.txt new.txt  
Node 10.72.12.150 found in old.txt but not in new.txt
Node 10.72.12.149 found in new.txt but not in old.txt
[10.72.12.148    State         ] Old = "enabled", new = "xenabled"
[10.72.7.122     Reason        ] Old = "Node address does not have service checking enabled", new = "xNode address does not have service checking enabled"

Ltm::Node注:両方の入力ファイルのデータは行のわずかな違いを除いて同じであるため、xいくつかのフィールドの前にを追加するためにnew.txtを編集していくつかの違いを作成する必要がありました。また、old.txtにノード10.172.12.150を追加し、new.txtに10.172.12.149を追加しました。

Perlハッシュは本質的に順序付けされていないので、実行ごとにノードの違いが異なる順序で印刷されることに注意する価値があります。配列を埋めるときにソートして%old一貫した順序を取得するのは簡単ですが、自然な@common_keysソート/バージョン管理ソートサブルーチンを実装する必要があります(またはそのいずれかを使用する必要があります)。自然選別モジュール存在するCPAN)IPアドレスが正しくソートされるようにします。この改善は読者の皆さんの練習用に残しておきます。この例ではこれは必要ありません。

印刷ステートメントを編集して、必要に応じて出力を変更できます。出力を指定しなかったため、違いを簡単に識別するために必要なものだけを印刷しました。

awkで同様のものを書くことは難しくありません(特にGNU awkは多次元配列を合理的にサポートしているので)。しかし、私はawkよりも冗長な傾向があるにもかかわらず、Perlを好む(実際には部分的に)。なぜならの)。

おすすめ記事