
로그 파일을 쉽게 추적하고 단일 필드의 출력을 화면에 인쇄하려고 합니다.
내 Linux 시스템의 로그 파일은 다음과 같습니다.
2022-10-21 16:00:08;areq_in=0;areq_qavg=0;areq_qmax=0;areq_sent=0;ares_out=0;ares_out_err=0;ares_out_ok=0;ares_qavg=0;ares_qmax=0;ares
_recv=0;ares_tavg=0;ares_tmax=0;creq_out=0;creq_qavg=0;creq_qmax=0;creq_recv=0;cres_in=0;cres_qavg=0;cres_qmax=0;cres_sent=0;lic_rej=0
;lic_use=0;mbr_from=0;mbr_to=0;mreject=0;mreject_conn=0;msys_recv=0;msys_sent=0;
로그의 각 줄은 ;
구분된 필드로 구성되며, 대부분은 "key=value" 형식입니다.
그래서 제가 하고 싶은 것은 creq_recv
화면에 "키" 이름에 대한 필드를 인쇄하는 것입니다.
누군가의 수정본에서 이 스크립트를 가져왔지만 뭔가 빠진 것 같습니다.
#!/bin/bash
creq_recv=$1
my_variable=`tail -f stats_2022102116.log | awk -F: -v creq_recv="$1" '$1 == creq_recv {$1=$1; print}' stats_2022102116.log`
echo "$my_variable"
출력이 비어 있기 때문에
[root@priti ]$ ./chk_conn_log.sh
[root@priti ]$
값이 무엇이든 출력은 화면에 인쇄되어야 합니다 creq_recv
. 예를 들어 아래와 같이
creq_recv=12
creq_recv=34
creq_recv=65
답변1
줄 및/또는 PCRE 또는 확장 정규 표현식의 일치하는 부분만 인쇄하는 옵션을 사용하여 grep
원하는 작업을 수행 할 수 있습니다. 이를 통해 "하나 이상의 비; 문자"를 사용할 수 있습니다.-o
-P
-E
[^;]+
tail -f stats_2022102116.log | grep -oP '(?<=^|;)creq_recv=[^;]+'
또는 보다 안전하기 위해 다음으로 끝나는 다른 필드 이름을 사용할 수도 있습니다 creq_recv
.
tail -f stats_2022102116.log | grep -oP '(^|;)\Kcreq_recv=[^;]+'
"awk 변수의 값을 스크립트에 전달된 첫 번째 인수의 값으로 설정"을 의미하기 awk
때문에 실패했습니다 . 하지만 시작한 스크립트에는 매개변수( ) 가 없으므로 비어 있으므로 역시 비어 있습니다.-v creq_recv="$1"
creq_recv
./chk_conn_log.sh
$1
creq_recv
어쨌든 변수가 설정되어 있어도 작동하지 않습니다. 스크립트가 awk
잘못되어 tail -f
중지하지 않으면 절대 종료되지 않으므로 echo
실행되지 않습니다. 당신이 원하는 것은 다음과 같습니다.
#!/bin/bash
tail -f stats_2022102116.log |
awk -F';' '{ for(i=1; i<=NF; i++){ if ($i ~ /^creq_recv=/) { print $i } } }'
아니요 echo
, tail
수정된 awk 스크립트만 해당됩니다. 하지만 위의 명령을 사용하면 grep
훨씬 간단합니다.
답변2
시도 중인 해결 방법에는 바람직하지 않은 동작을 발생시키는 몇 가지 문제가 포함되어 있습니다.
- 스크립트에
$1
호출할 때 지정하지 않은 것 같은 명령줄 인수("bash" 수준)가 필요합니다../chk_conn_log.sh
- 스크립트는 해당 (지정되지 않음=null) 값을 다음으로 복사합니다.껍데기바꾸다
creq_recv
. 그래서,creq_recv
쉘에 관한 한는 빈 변수입니다. - 필터링하고 싶어?전진프로세스의 출력을 인쇄
tail
하지만 나중에 인쇄에 사용되는 쉘 변수에 결과를 할당합니다echo
. 변수는 두 프로세스가 모두 종료될 때만 채워지기 때문에 작동하지 않습니다. 그러나 로그 파일에 더 이상 쓰기가 이루어지지 않으면tail
새 입력을 기다리게 됩니다. 따라서 로그 파일은 절대 종료되지 않으며 스크립트는회의실제로는 거기에 갇혀 있지만, tail
의 출력을 로 파이프하고 싶지만awk
로그 파일을 매개변수로 명시적으로 선언하므로awk
파일 내용이 간단히 실행됩니다.지금 스크립트를 호출하는 것처럼, 아직 행이 포함되어 있지 않을 수 있으며 종료됩니다. 따라서 변수는my_variable
비어 있고 스크립트의 출력도 비어 있습니다.
비록 그렇다 하더라도,
- 로그 파일이 구분되어 있다고 말했지만(예제 표시) 구분 기호를 사용하도록
;
표시했습니다 .awk
:
- 당신이 설정한awk 변수
creq_recv
(지정되지 않은) 명령줄 인수에 추가하고awk
프로그램 내부에서첫 번째:
- 콘텐츠와 동일한 별도의 필드앗바꾸다creq_recv
. 그러나 변수는 비어 있고(위 참조) "필드"에는 문자열2022-10-21 16
(첫 번째 날짜/시간까지:
)이 포함됩니다. 따라서 여러 가지 이유로 조건이 충족되지 않습니다. 해당 줄을 포함하여 스크립트를 호출하면 출력이 비어 있습니다. - 표시된 필드뿐만 아니라 전체 행을 인쇄합니다
creq_recv=xx
.
즉, 무엇내 생각엔 당신이 이루고 싶어하는 것 같아요이 작업은 다음과 같이 수행할 수 있습니다.
tail -f stats_2022102116.log | awk -F';' '{for (i=1;i<=NF;i++) {if (index($i,"creq_recv=")==1) print $i}}'
- 그러면 필드 구분 기호가 로 설정됩니다
;
. - 그런 다음 각 (들어오는) 입력 줄에 대해 모든 필드를 반복하고
creq_recv=
문자열로 시작하는 경우 필드를 인쇄합니다.
정규식 일치 대신 리터럴 문자열 비교를 사용하기로 선택한 이유는 (일반적인 경우) 정규식에서 특별한 의미가 있는 문자가 포함된 문자열을 이스케이프하지 않고도 찾을 수 있기 때문입니다. 정규식 일치가 필요한 경우(귀하의 게시물에 따르면 여기에서는 해당되지 않음) 변경할 수 있습니다.
if (index($i,"creq_recv=")==1)
도착하다
if ($i ~ /your regular expression/)
답변3
사용행복하다(이전 Perl_6)
#recover all key/value pairs:
~$ cat file | raku -e 'my @a = lines>>.split(";", :skip-empty)>>.[1..*].flat; \
my %hash; for @a>>.split("=") {%hash.=append: $_}; \
.say for %hash.sort;'
#recover values for specific key:
~$ cat file | raku -e 'my @a = lines>>.split(";", :skip-empty)>>.[1..*].flat; \
my %hash; for @a>>.split("=") {%hash.=append: $_}; \
say %hash<creq_recv>;'
위 내용은 Perl 프로그래밍 언어 계열인 Raku로 코딩된 답변입니다. 이 문제에는 실제로 키-값 솔루션이 필요하며 Raku는 실망하지 않습니다.
위의 두 코드 예제는 마지막 문을 제외하고 동일합니다. 즉, lines
읽은 파일은 기본적으로 후행 줄 바꿈을 자르는 효과가 있습니다 \n
. 그런 다음 이 입력은 세미콜론으로 분할되어 첫 번째(시간/날짜) 요소를 제거하고 유지 관리되며 배열 에 저장되는 인덱스 요소를 ;
생성합니다 . 그런 다음 의 요소는 등호 로 개별적으로 나뉩니다. 이 결과 요소는 편집 됩니다.[1..*]
flat
@a
@a
>>
=
append
모두이 방식으로 입력이 주어 지면 %hash
Raku는 두 개의 연속 요소마다 키/값 쌍을 생성합니다.
첫 번째 코드 예제에서는 모든 키/값 쌍이 반환됩니다. 두 번째 코드 예제에서는 creq_recv
키와 연결된 값만 반환됩니다.
입력 예:
2022-10-21 16:00:08;areq_in=0;areq_qavg=0;areq_qmax=0;areq_sent=0;ares_out=0;ares_out_err=0;ares_out_ok=0;ares_qavg=0;ares_qmax=0;ares_recv=0;ares_tavg=0;ares_tmax=0;creq_out=0;creq_qavg=0;creq_qmax=0;creq_recv=0;cres_in=0;cres_qavg=0;cres_qmax=0;cres_sent=0;lic_rej=0;lic_use=0;mbr_from=0;mbr_to=0;mreject=0;mreject_conn=0;msys_recv=0;msys_sent=0;
첫 번째 코드 예제의 샘플 출력(두 번째 코드 예제에서 반환됨 0
):
areq_in => 0
areq_qavg => 0
areq_qmax => 0
areq_sent => 0
ares_out => 0
ares_out_err => 0
ares_out_ok => 0
ares_qavg => 0
ares_qmax => 0
ares_recv => 0
ares_tavg => 0
ares_tmax => 0
creq_out => 0
creq_qavg => 0
creq_qmax => 0
creq_recv => 0
cres_in => 0
cres_qavg => 0
cres_qmax => 0
cres_sent => 0
lic_rej => 0
lic_use => 0
mbr_from => 0
mbr_to => 0
mreject => 0
mreject_conn => 0
msys_recv => 0
msys_sent => 0
더 풍부한 반환 정보를 얻으려면 Raku의 =>
쌍 생성자를 사용하여 마지막 문을 다음과 같이 변경하세요.
$_ = "creq_recv" andthen say $_ => %hash{$_};
...반품:
creq_recv => 0
마지막으로 Raku는 수신 (예: StdIN을 통해 수신된 라인)하고 수신된 라인에서 코드를 실행하도록 react
설계할 수 있는 블록을 구현합니다. 이와 같이:Supply
$*IN.lines
whenever
~$ tail -f test.log | raku -e 'react {whenever Supply( $*IN.lines ) { \
my @a = $_.map( *.split(";", :skip-empty).[1..*] ).flat; \
my %hash; for @a.map: *.split("=") { %hash.=append: $_ }; \
$_ = "creq_recv" andthen say $_ => %hash{$_} // Nil; } };'
creq_recv => 0
creq_recv => 0
^C
https://docs.raku.org/언어/concurrency#react
https://docs.raku.org/언어/hashmap
https://docs.raku.org/routine/=%3E
https://raku.org
추신: brian d foy의 책에는 "연관"(예: 해시 및 맵)에 대한 매우 훌륭한 장이 있습니다.Perl6 배우기.