awk를 사용하여 이 5분을 기록하고 출력을 다른 파일로 변환하려면 어떻게 해야 합니까?

awk를 사용하여 이 5분을 기록하고 출력을 다른 파일로 변환하려면 어떻게 해야 합니까?

다음 내용이 포함된 listlog라는 로그 파일이 있습니다.

2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
line 3
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid
line 3

t1과 t2 사이에 기록된 로그를 필터링하여 2개의 연속 로그 라인을 인쇄하고 싶습니다. 나는 awk와 if 조건과 grep을 사용하여 작성합니다. 하지만 오류가 발생했습니다.

이것이 t1 < (16:09:17, 16:19:17) < t2 라고 가정하고 필터링하여 새 파일에 쓰고 싶은 내용입니다.

2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid

이것은 내가 작성한 awk 스크립트입니다.

t1=$(date -d "$min_change minutes ago" +"%F %T")
t2=$(date +"%F %T")
cat $listlog | awk -v t1="$t1" -v t2="$t2" -v listlog="$listlog" '{
        if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
        {
                if ( $0 > t1 && $0 < t2 | $0 ~ t2 )
                {
                        grep -A 2 $0 $listlog >> /tmp/temp.txt
                }
        }
        }'

내가 얻는 오류는 다음과 같습니다.

awk: cmd. line:2:       if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
awk: cmd. line:2:                       ^ unterminated regexp
awk: cmd. line:3:       if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
awk: cmd. line:3:                                                ^ unexpected newline or end of string
awk: cmd. line:4:               if ( $0 > t1 && $0 < t2 | $0 ~ t2 )
awk: cmd. line:4:                                         ^ syntax error.
awk: cmd. line:5:               if ( $0 > t1 && $0 < t2 | $0 ~ t2 ) 
awk: cmd. line:5:                                                   ^ unexpected newline or end of string
awk: cmd. line:6:                       grep -A 2 $0 $listlog >> /temp/temp.txt
awk: cmd. line:6:                                             ^ syntax error
awk: cmd. line:7:                       grep -A 2 $0 $listlog >> /temp/temp.txt.
awk: cmd. line:7:                                                                ^ unexpected newline or end of string

답변1

스크립트의 문제점을 설명하기 시작하는 것조차 어렵지만 다음은 가장 중요한 사항을 요약한 것입니다.

  1. awk당신이 쓴 것은 대본 이 아닙니다 . awk쉘 스크립트에 포함된 스크립트 도 아닙니다 (보통 완벽하게 괜찮습니다). 이는 일부 쉘 코드와 awk그 안에 쉘 코드를 포함시키려는 시도의 이상한 혼합입니다 ( awk쉘 명령을 해석하거나 실행하지 않고).

    어쨌든 외부 프로세스로 포크하지 않고는 grep내부적으로 이와 같이 실행할 수 없습니다 . 그리고 정규식 패턴 일치가 가능하므로 awk이 작업을 수행할 필요가 없습니다 .awk

  2. 코드에는 들여쓰기가 없으므로 읽기가 매우 어렵습니다.

    업데이트: 방금 질문을 편집하여 형식을 변경했는데 코드에 들여쓰기가 있는 것으로 나타났습니다. 하지만 <br/>Markdown 편집기에 내장된 텍스트 서식 지정 기능을 사용하는 대신 HTML 태그를 사용하여 서식을 지정합니다 .

  3. 1번과 2번 항목은 아마도 질문을 게시한 후 7시간 이내에 답변이나 댓글을 받지 못한 이유일 것입니다. 모든 독자(적어도 내 독자)의 초기 반응은 "WTF? 이건 말도 안 돼. 어디서부터 시작해야 할지조차 모르겠어... 통과"입니다.

  4. 셸에서 또는 날짜 awk비교를 시도하여 날짜 비교를 수행할 수 없습니다. 보다 큼 또는 보다 작음과 같은 숫자 비교를 수행하려면 날짜를 숫자로 변환해야 합니다(예: time_t1970년 1월 1일 자정(UTC)인 "epoch" 이후의 초를 나타내는 unix 형식).

  5. 에서 원하는 대로 할 수는 있지만 날짜 변환 기능이 내장되어 있지 않기 awk때문에 필요 이상으로 어려울 것입니다 . 날짜 및 시간 라이브러리 기능이 좋은 awk에서는 훨씬 쉬울 것입니다 . perl여러분이 작성하는 스크립트는 perl코드보다 코드 스타일에 더 가깝기 때문에 이는 여러분에게 좋은 일입니다 awk.


이것은 Perl에서 원하는 것을 달성하는 매우 간단하고 직접적인 방법입니다. 명령줄 인수가 필요합니다(perl의GetSelect::표준라이브러리 모듈). Getopt::StdPerl에 포함된 핵심 Perl 라이브러리 모듈입니다.

매개변수는 순서에 관계없이 제공될 수 있습니다. 모든 옵션 매개변수( , 및 ) -m-n필수 가 아니며 -s명령줄에 제공되지 않은 경우 기본값을 갖습니다. 처리되지 않은 인수는 Getopt::Std입력 파일 이름으로 처리됩니다. 스크립트는 표준 입력은 물론 모든 입력 파일 이름을 처리할 수 있으므로 로그 파일을 스크립트로 연결할 수 있습니다.

스크립트는 또한날짜::분석Perl의 모듈시간::날짜날짜 문자열을 epoch 이후의 초 컬렉션으로 변환합니다.

Date::ParsePerl에는 이를 포함하지 않으므로 설치해야 합니다. Debian(또는 Ubuntu, Mint 또는 기타 Debian 관련 배포판)을 사용하는 경우 sudo apt-get install libtimedate-perl대부분의 다른 배포판에서도 이를 패키지로 제공합니다. 센토스 패키지는Perl-TimeDate-2.30-2Centos 7의 경우 또는Perl-TimeDate-2.30-15센토스 8의 경우. 그렇지 않으면 를 사용할 수 있습니다 cpan.

#!/usr/bin/perl
use strict;
use Getopt::Std;
use Date::Parse;

my %opts;
getopt('m:s:n:', \%opts); # -m minutes, -s start time, -n number of lines

my $st  = $opts{s} || -1; # start time, default now.
my $min = $opts{m} ||  5; # number of minutes after $st to match, default 5.
my $nl  = $opts{n} ||  2; # No. of extra lines to print after match, default 2.

if ($st == -1) {
  $st = time();           # now
} else {
  $st = str2time($st);    # convert time string to seconds since epoch
};
my $et = $st + $min * 60; # calculate ending time

my $p = -1; # input lines are printed only when $p > -1

# main loop, read and process all input file(s).
while (<>) {
  if (m/^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)/) {
    my $t = str2time($1);
    $p = $nl if ($t >= $st && $t <= $et);
  };

  if ($p > -1) { print; $p-- };
};

예를 들어 다른 이름으로 저장하고 extract.pl실행 가능하게 만들고 chmod +x extract.pl다음과 같이 실행합니다.

$ ./extract.pl -s "2021-08-12 16:09:00" -n 2 -m 5 listlog 
2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid

>>/tmp/temp.txt원하는 경우 명령줄 끝에 추가하여 출력을 리디렉션할 수 있습니다 .

관련 정보