복잡한 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를 시도했는데 모든 행을 표시할 수 있지만 노드가 천 개가 넘고 시간이 오래 걸립니다. Ltm::Node: (10.47.63.133)를 인덱스로 사용하여 이전 버전과 새 버전을 일치시키세요. 그러면 아래의 모든 항목을 비교하여 일치하지 않는 항목이 있는지 확인합니다.

혼란을 드려 죄송합니다..이 두통을 어떻게 설명해야 할지 모르겠습니다.

답변1

이 데이터는 다중 레벨 연관 배열(또는 Perl 용어로 Hash-of-Hashes/HoH, 참조)로 사용 가능합니다.페르츠카, Perl 데이터 구조 매뉴얼), 첫 번째 수준 키는 노드 이름이고 두 번째 수준 키(아래 스크립트에서 "하위 키"라고 함)는 관련 필드 이름(가용성, 상태, 이유 등)입니다.

예를 들어:

#!/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을 선호합니다(실제로 부분적으로).왜냐하면의).

관련 정보