다음 내용이 포함된 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
스크립트의 문제점을 설명하기 시작하는 것조차 어렵지만 다음은 가장 중요한 사항을 요약한 것입니다.
awk
당신이 쓴 것은 대본 이 아닙니다 .awk
쉘 스크립트에 포함된 스크립트 도 아닙니다 (보통 완벽하게 괜찮습니다). 이는 일부 쉘 코드와awk
그 안에 쉘 코드를 포함시키려는 시도의 이상한 혼합입니다 (awk
쉘 명령을 해석하거나 실행하지 않고).어쨌든 외부 프로세스로 포크하지 않고는
grep
내부적으로 이와 같이 실행할 수 없습니다 . 그리고 정규식 패턴 일치가 가능하므로awk
이 작업을 수행할 필요가 없습니다 .awk
코드에는 들여쓰기가 없으므로 읽기가 매우 어렵습니다.
업데이트: 방금 질문을 편집하여 형식을 변경했는데 코드에 들여쓰기가 있는 것으로 나타났습니다. 하지만
<br/>
Markdown 편집기에 내장된 텍스트 서식 지정 기능을 사용하는 대신 HTML 태그를 사용하여 서식을 지정합니다 .1번과 2번 항목은 아마도 질문을 게시한 후 7시간 이내에 답변이나 댓글을 받지 못한 이유일 것입니다. 모든 독자(적어도 내 독자)의 초기 반응은 "WTF? 이건 말도 안 돼. 어디서부터 시작해야 할지조차 모르겠어... 통과"입니다.
셸에서 또는 날짜
awk
비교를 시도하여 날짜 비교를 수행할 수 없습니다. 보다 큼 또는 보다 작음과 같은 숫자 비교를 수행하려면 날짜를 숫자로 변환해야 합니다(예:time_t
1970년 1월 1일 자정(UTC)인 "epoch" 이후의 초를 나타내는 unix 형식).에서 원하는 대로 할 수는 있지만 날짜 변환 기능이 내장되어 있지 않기
awk
때문에 필요 이상으로 어려울 것입니다 . 날짜 및 시간 라이브러리 기능이 좋은awk
에서는 훨씬 쉬울 것입니다 .perl
여러분이 작성하는 스크립트는perl
코드보다 코드 스타일에 더 가깝기 때문에 이는 여러분에게 좋은 일입니다awk
.
이것은 Perl에서 원하는 것을 달성하는 매우 간단하고 직접적인 방법입니다. 명령줄 인수가 필요합니다(perl의GetSelect::표준라이브러리 모듈). Getopt::Std
Perl에 포함된 핵심 Perl 라이브러리 모듈입니다.
매개변수는 순서에 관계없이 제공될 수 있습니다. 모든 옵션 매개변수( , 및 ) -m
는 -n
필수 가 아니며 -s
명령줄에 제공되지 않은 경우 기본값을 갖습니다. 처리되지 않은 인수는 Getopt::Std
입력 파일 이름으로 처리됩니다. 스크립트는 표준 입력은 물론 모든 입력 파일 이름을 처리할 수 있으므로 로그 파일을 스크립트로 연결할 수 있습니다.
스크립트는 또한날짜::분석Perl의 모듈시간::날짜날짜 문자열을 epoch 이후의 초 컬렉션으로 변환합니다.
Date::Parse
Perl에는 이를 포함하지 않으므로 설치해야 합니다. 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
원하는 경우 명령줄 끝에 추가하여 출력을 리디렉션할 수 있습니다 .