로그 파일에서 처음 나타나는 문자열을 찾고, T/F 값을 변수로 설정하고, 발생한 변경 사항을 기록하는 방법

로그 파일에서 처음 나타나는 문자열을 찾고, T/F 값을 변수로 설정하고, 발생한 변경 사항을 기록하는 방법

이 헤더의 이름을 어떻게 지정해야 할지 모르겠지만 제가 얻은 것은 다음과 같습니다.

다음 텍스트가 포함된 파일:

[10:03:43] 10:03:35 22JUN22  ConUP     CW1B1 T     CW1B3 T     CW1B5 T     CW1B7 T  
[10:03:44]                          CW2B1 T     CW2B4 T     CW2B5 T     CW2B7 T  
[10:03:44]                          CW3B1 T     CW3B4 T     CW3B5 T     CW4B4 T  
[10:03:44]                          CW4B8 T     CW5B4 T     CW5B8 T     CW6B4 T  
[10:03:44]                          CW6B8 T     CW7B8 T     CW8B4 T     CW8B8 T  
[10:03:44]                          CW9B4 T     CW9B8 T    CW10B4 T    CW10B8 T  
[10:03:44]                         CW11B4 T    CW11B8 T    CW12B4 T    CW12B8 T   
[10:04:16] 10:04:28 22JUN22  ConUP     CW1B1 T     CW1B3 T     CW1B5 T     CW1B7 T  
[10:04:36]                          CW2B1 F     CW2B3 F     CW2B5 F     CW2B7 F  
[10:04:36]                          CW3B1 T     CW3B4 T     CW3B5 T     CW4B4 T  
[10:04:36]                          CW4B8 T     CW5B4 T     CW5B8 T     CW6B4 T  
[10:04:37]                          CW6B8 T     CW7B8 T     CW8B4 T     CW8B8 T  
[10:04:37]                          CW9B4 T     CW9B8 T    CW10B4 T    CW10B8 T  
[10:04:37]                         CW11B4 T    CW11B8 T    CW12B4 T    CW12B8 T  

그런 다음 실제 파일은 True 및 False 값의 변경 사항으로 채워집니다.

a에 True 항목이 있고 마지막 항목 이후 변경되지 않은 경우에는 해당 항목을 제거하고 값이 False로(또는 False에서 True로) 변경될 때만 유지하고 싶습니다.

아이디어는 문자열(예: CW1B1)의 첫 번째 항목을 찾은 다음 그 뒤에 오는 T 또는 F 값을 변수로 저장해야 한다는 것입니다. 그런 다음 다음에 나타나는 항목을 확인하고 T/F 값을 비교하십시오. 동일하면 잘라내기 또는 보내기를 사용하여 항목을 삭제하고 다음 항목을 찾으십시오. 값이 변경된 경우 무시하고 계속하십시오.

예상 출력:

[10:03:43] 10:03:35 22JUN22  ConUP     CW1B1 T     CW1B3 T     CW1B5 T     CW1B7 T  
[10:03:44]                          CW2B1 T     CW2B4 T     CW2B5 T     CW2B7 T  
[10:03:44]                          CW3B1 T     CW3B4 T     CW3B5 T     CW4B4 T  
[10:03:44]                          CW4B8 T     CW5B4 T     CW5B8 T     CW6B4 T  
[10:03:44]                          CW6B8 T     CW7B8 T     CW8B4 T     CW8B8 T  
[10:03:44]                          CW9B4 T     CW9B8 T    CW10B4 T    CW10B8 T  
[10:03:44]                         CW11B4 T    CW11B8 T    CW12B4 T    CW12B8 T   
[10:04:16] 10:04:28 22JUN22  ConUP       
[10:04:36]                          CW2B1 F     CW2B3 F     CW2B5 F     CW2B7 F  
[10:04:36]                          
[10:04:36]                          
[10:04:37]                          
[10:04:37]                          
[10:04:37]                         

어쩌면 더 좋은 방법이 있을 수도 있지만 여전히 프레임워크에 대한 도움이 필요하며 스크립트에 필요한 모든 가능한 변수를 생성할 수 있습니다.

답변1

이것은 아마도 당신이 원하는 것일 것입니다(테스트 가능한 예제 입력/출력이 제공되지 않으므로 테스트되지 않음).

awk '
    {
        for ( i=2; i<=NF; i++ ) {
            if ( $i ~ /^[TF]$/ ) {
                tag = $(i-1)
                val = $i
                if ( map[tag] == val ) {
                    $(i-1) = $i = ""
                }
                map[tag] = val
                i++
            }
        }
        $0 = $0
        $1 = $1
        print
    }
' file

답변2

사용행복하다(이전 Perl_6)

raku -e 'my @a = words;  @a.splice(1, *-128);  @a.splice(64,*-62);  \
         @a.=rotor(9); @a = @a>>.[1..*-1].flat.rotor(2); my @b; for 0..27 -> $i {  \
         @a[$i] eq @a[$i+28] ?? @b.push(@a[$i]~"+") !! @b.push(@a[$i+28]~"x") }; \
         .say for @b.rotor(4)>>.join("\t|\t");'  

산출:

CW1B1 T+    |   CW1B3 T+    |   CW1B5 T+    |   CW1B7 T+
CW2B1 Fx    |   CW2B3 Fx    |   CW2B5 Fx    |   CW2B7 Fx
CW3B1 T+    |   CW3B4 T+    |   CW3B5 T+    |   CW4B4 T+
CW4B8 T+    |   CW5B4 T+    |   CW5B8 T+    |   CW6B4 T+
CW6B8 T+    |   CW7B8 T+    |   CW8B4 T+    |   CW8B8 T+
CW9B4 T+    |   CW9B8 T+    |   CW10B4 T+   |   CW10B8 T+
CW11B4 T+   |   CW11B8 T+   |   CW12B4 T+   |   CW12B8 T+

Raku를 사용하는 아이디어는 다음과 같습니다. 기본적으로 코드는 tail로그 파일에서 실행할 수 있는 대시보드를 구축합니다. 입력을 받아 분해한 후 배열 words에 할당합니다 . @a행 1과 8에서 splice추가 3개를 제거하는 데 사용됩니다 words. 이제 몇 가지 재배열을 통해 1) 를 사용하여 9개 요소로 구성된 행을 다시 생성한 rotor(9)다음 2) 첫 번째 열을 제거하고 나머지 8개 열을 2개 요소로 구성된 행으로 쌍을 이룰 수 있습니다(예: ) ("CW1B1", "T"), ("CW1B3", "T"), ("CW1B5", "T")....

이 시점부터 번호가 매겨진 28개의 요소가 있다는 것을 알 수 있습니다 0..27. 28개 요소에 대한 반복을 사용하여 eq및 사이의 문자열 동일성을 검색합니다 . "Test True False"인 Raku의 삼항 연산자는 True이면 첫 번째 문자열을 배열에 푸시하고(두 값이 모두 변경되지 않은 상태로 유지된다는 의미를 추가함), False이면 두 번째 문자를 푸시합니다. 문자열이 배열에 푸시됩니다( 값이 변경되었음을 나타내기 위해 a가 추가됩니다. 그런 다음 행(with)을 다시 행당 4쌍으로 다시 정렬하고 인쇄합니다.@a[$i]@a[$i+28]??!!@b+@bxrotor(4)


입력 예:

[10:03:43] 10:03:35 22JUN22  ConUP     CW1B1 T     CW1B3 T     CW1B5 T     CW1B7 T  
[10:03:44]                          CW2B1 T     CW2B4 T     CW2B5 T     CW2B7 T  
[10:03:44]                          CW3B1 T     CW3B4 T     CW3B5 T     CW4B4 T  
[10:03:44]                          CW4B8 T     CW5B4 T     CW5B8 T     CW6B4 T  
[10:03:44]                          CW6B8 T     CW7B8 T     CW8B4 T     CW8B8 T  
[10:03:44]                          CW9B4 T     CW9B8 T    CW10B4 T    CW10B8 T  
[10:03:44]                         CW11B4 T    CW11B8 T    CW12B4 T    CW12B8 T   
[10:04:16] 10:04:28 22JUN22  ConUP     CW1B1 T     CW1B3 T     CW1B5 T     CW1B7 T  
[10:04:36]                          CW2B1 F     CW2B3 F     CW2B5 F     CW2B7 F  
[10:04:36]                          CW3B1 T     CW3B4 T     CW3B5 T     CW4B4 T  
[10:04:36]                          CW4B8 T     CW5B4 T     CW5B8 T     CW6B4 T  
[10:04:37]                          CW6B8 T     CW7B8 T     CW8B4 T     CW8B8 T  
[10:04:37]                          CW9B4 T     CW9B8 T    CW10B4 T    CW10B8 T  
[10:04:37]                         CW11B4 T    CW11B8 T    CW12B4 T    CW12B8 T  

https://stackoverflow.com/questions/3416467/how-to-tail-f-the-latest-log-file-with-a-given-pattern
https://docs.raku.org/routine/splice
https://docs.raku.org/언어/operators#index-entry-operator_ternary
https://raku.org

답변3

다음 Perl 스크립트는 각 입력 줄에서 중복된 변수 값을 제거합니다. 이전에 본 적이 없거나 마지막으로 본 이후 변경된 변수만 출력에 포함됩니다. 빈 줄(즉, 새 변수나 변경된 변수가 없는 줄)은 인쇄되지 않습니다.

$ cat remove-dupes.pl 
#!/usr/bin/perl

use strict;

# %vars is a hash (associative array) to store last-seen T/F values
# for the "variables".  This is global in scope, i.e. defined here
# outside of the main loop because its keys & values need to be
# remembered across lines.
my %vars;

# read in and process each input line
while(<>) {
  chomp; # remove newline character at end of line

  # @out is an array to hold "VAR [TF]" values that we either
  # haven't seen before or have changed since last time we saw
  # them.  i.e. the values we want to output.  It needs to be
  # reset to empty every time we read a line.
  my @out = ();

  # extract the first word (i.e. "ConUp") from input line
  # by deleting all "VAR [TF]" strings from the line
  my $first_word = $_;
  $first_word =~ s/ ?\w+\s+[TF]//g;
  # add it to @out if it isn't empty
  push @out, $first_word if $first_word;

  # Iterate over each "VAR [TF]" string in the line. Split
  # it into the key (variable name) and value (T or F).
  # If it's new or changed then add it to @out and
  # remember its current value in %vars
  while (/ ?\b(\w+ [TF])\b/g) {
    my ($key,$val) = split / /, $1;
    next if ($vars{$key} eq $val);
    push @out, $1;
    $vars{$key} = $val;
  };

  # join (with spaces) and print @out if it isn't empty.
  if (@out) {print join(" ",@out), "\n"};
}

참고: 줄에 "VAR[TF]"가 아닌 다른 문자열이 있으면 출력에서 ​​해당 줄의 시작 부분으로 이동됩니다. 이는 버그로 간주될 수도 있고 그렇지 않을 수도 있습니다. 샘플 데이터의 유일한 인스턴스는 첫 번째 줄 시작 부분에 있는 "ConUp"이므로 필요에 따라 작동합니다. 변수를 호출하면 안 되지만 $first_word이 방법이 더 좋습니다.$anything_that_doesnt_match_a_boolean_variable_pattern

입력 파일에는 제거해야 할 중복 변수 값이 포함되어 있지 않으므로 해당 값이 포함된 파일을 생성했습니다(그리고 변경될 일부 변수 인스턴스를 추가했습니다).

$ cat file2.txt 
ConUp  CW1B1 T CW1B2 T CW1B3 F CW1B4 F
CW2B1 T CW2B2 F CW2B3 F CW2B4 T
CW2B1 F CW2B2 F CW2B3 F CW2B4 T
CW2B1 F CW2B2 F CW2B3 F CW2B4 T
CW2B1 T CW2B2 F CW2B3 F CW2B4 T
CW2B1 F CW2B2 F CW2B3 T CW2B4 T

예제 출력:

$ ./remove-dupes.pl file2.txt 
ConUp  CW1B1 T CW1B2 T CW1B3 F CW1B4 F
CW2B1 T CW2B2 F CW2B3 F CW2B4 T
CW2B1 F
CW2B1 T
CW2B1 F CW2B3 T

업데이트된 버전:

이 버전은 각 줄의 처음 34자를 "첫 번째 단어"로 추출합니다. 이는 sprintf()각 요소를 @out10자 너비 문자열로 형식화하는 데 사용되며 출력에서 ​​후행 공백을 제거합니다. \s*또한 \s+단일 공백 ​​대신 합계를 사용하여 공백 문자를 일치시키거나 분할합니다. 원본 스크립트의 설명이 여전히 적용되므로(사소한 변경 사항 포함) 간결성을 위해 설명을 제거했습니다.

$ cat remove-dupes2.pl 
#!/usr/bin/perl

use strict;
my %vars;

while(<>) {
  chomp;
  my @out = ();

  my $first_word;
  ($first_word = $_) =~ s/\b\w+\s+[TF]//g;
  $first_word =~ s/^(.{34})\s+$/$1 /;
  push @out, $first_word if $first_word;

  while (/\s*\b(\w+\s+[TF])\b/g) {
    my ($key,$val) = split /\s+/, $1;
    next if ($vars{$key} eq $val);
    push @out, sprintf("%-10s",$1);
    $vars{$key} = $val;
  };

  my $out = join(" ",@out);
  $out =~ s/\s+$//; # remove trailing spaces
  print "$out\n";
}

새로운 입력 데이터를 사용한 출력 예( input.txt). 아직은 아니야정확히예제 출력과 동일하지만 여전히 약간의 공백 차이가 있지만 출력은 위의 원본 스크립트 출력보다 훨씬 가깝습니다.

$ ./remove-dupes2.pl input.txt 
[10:03:43] 10:03:35 22JUN22  ConUP  CW1B1 T    CW1B3 T    CW1B5 T    CW1B7 T
[10:03:44]                          CW2B1 T    CW2B4 T    CW2B5 T    CW2B7 T
[10:03:44]                          CW3B1 T    CW3B4 T    CW3B5 T    CW4B4 T
[10:03:44]                          CW4B8 T    CW5B4 T    CW5B8 T    CW6B4 T
[10:03:44]                          CW6B8 T    CW7B8 T    CW8B4 T    CW8B8 T
[10:03:44]                          CW9B4 T    CW9B8 T    CW10B4 T   CW10B8 T
[10:03:44]                          CW11B4 T   CW11B8 T   CW12B4 T   CW12B8 T
[10:04:16] 10:04:28 22JUN22  ConUP
[10:04:36]                          CW2B1 F    CW2B3 F    CW2B5 F    CW2B7 F
[10:04:36]
[10:04:36]
[10:04:37]
[10:04:37]
[10:04:37]

[HH:MM::SS]그런데, 거의 빈 줄(포함된 줄만)을 인쇄하고 싶지 않다면 print "$out\n";줄을 print "$out\n" unless ($out =~ /^\[[^]]\]\s*$/);.

유일한 차이점을 확인 하려면 diff공백( output.txt예제 출력)입니다.

$ ./remove-dupes2.pl input.txt > out.txt
$ diff --ignore-space-change -u output.txt out.txt
$ 

관련 정보