데이터 스트림의 문자열을 필터링하고 화면에 출력하기 위한 쉘 스크립트

데이터 스트림의 문자열을 필터링하고 화면에 출력하기 위한 쉘 스크립트

로그 파일을 쉽게 추적하고 단일 필드의 출력을 화면에 인쇄하려고 합니다.

내 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$1creq_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. 스크립트에 $1호출할 때 지정하지 않은 것 같은 명령줄 인수("bash" 수준)가 필요합니다../chk_conn_log.sh
  2. 스크립트는 해당 (지정되지 않음=null) 값을 다음으로 복사합니다.껍데기바꾸다 creq_recv. 그래서,creq_recv 쉘에 관한 한는 빈 변수입니다.
  3. 필터링하고 싶어?전진프로세스의 출력을 인쇄 tail하지만 나중에 인쇄에 사용되는 쉘 변수에 결과를 할당합니다 echo. 변수는 두 프로세스가 모두 종료될 때만 채워지기 때문에 작동하지 않습니다. 그러나 로그 파일에 더 이상 쓰기가 이루어지지 않으면 tail새 입력을 기다리게 됩니다. 따라서 로그 파일은 절대 종료되지 않으며 스크립트는회의실제로는 거기에 갇혀 있지만,
  4. tail의 출력을 로 파이프하고 싶지만 awk로그 파일을 매개변수로 명시적으로 선언하므로 awk파일 내용이 간단히 실행됩니다.지금 스크립트를 호출하는 것처럼, 아직 행이 포함되어 있지 않을 수 있으며 종료됩니다. 따라서 변수는 my_variable비어 있고 스크립트의 출력도 비어 있습니다.

비록 그렇다 하더라도,

  1. 로그 파일이 구분되어 있다고 말했지만(예제 표시) 구분 기호를 사용하도록 ;표시했습니다 .awk:
  2. 당신이 설정한awk 변수 creq_recv(지정되지 않은) 명령줄 인수에 추가하고 awk프로그램 내부에서첫 번째 :- 콘텐츠와 동일한 별도의 필드바꾸다 creq_recv. 그러나 변수는 비어 있고(위 참조) "필드"에는 문자열 2022-10-21 16(첫 번째 날짜/시간까지 :)이 포함됩니다. 따라서 여러 가지 이유로 조건이 충족되지 않습니다. 해당 줄을 포함하여 스크립트를 호출하면 출력이 비어 있습니다.
  3. 표시된 필드뿐만 아니라 전체 행을 인쇄합니다 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모두이 방식으로 입력이 주어 지면 %hashRaku는 두 개의 연속 요소마다 키/값 쌍을 생성합니다.

첫 번째 코드 예제에서는 모든 키/값 쌍이 반환됩니다. 두 번째 코드 예제에서는 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.lineswhenever

~$ 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 배우기.

관련 정보