쉘 스크립트/Regex : 여러 줄에 대한 추출
문제
실패한 이벤트를 추출하기 위해 로그 구문 분석 스크립트를 작성하려고합니다. 나는 이것들을 grep으로 가져올 수 있습니다 :
$ grep -A5 "FAILED" log.txt
2008-08-19 17:50:07 [7052] [14] DEBUG: data: 3a 46 41 49 4c 45 44 20 20 65 72 72 3a 30 32 33 :FAILED err:023
2008-08-19 17:50:07 [7052] [14] DEBUG: data: 20 74 65 78 74 3a 20 00 text: .
2008-08-19 17:50:07 [7052] [14] DEBUG: Octet string dump ends.
2008-08-19 17:50:07 [7052] [14] DEBUG: SMPP PDU dump ends.
2008-08-19 17:50:07 [7052] [14] DEBUG: SMPP[test] handle_pdu, got DLR
2008-08-19 17:50:07 [7052] [14] DEBUG: DLR[internal]: Looking for DLR smsc=test, ts=1158667543, dst=447872123456, type=2
--
2008-08-19 17:50:07 [7052] [8] DEBUG: data: 3a 46 41 49 4c 45 44 20 20 65 72 72 3a 30 32 34 :FAILED err:024
2008-08-19 17:50:07 [7052] [8] DEBUG: data: 20 74 65 78 74 3a 20 00 text: .
2008-08-19 17:50:07 [7052] [8] DEBUG: Octet string dump ends.
2008-08-19 17:50:07 [7052] [8] DEBUG: SMPP PDU dump ends.
2008-08-19 17:50:07 [7052] [8] DEBUG: SMPP[test] handle_pdu, got DLR
2008-08-19 17:50:07 [7052] [8] DEBUG: DLR[internal]: Looking for DLR smsc=test, ts=1040097716, dst=447872987654, type=2
내가 관심있는 것은 각 블록마다 오류 코드 (예 : 첫 번째 줄의 "023"부분 ": 실패 ERR : 023"및 DST 번호 (예 : DST = 447872123456”의 DST 번호 (예 : 447872123456”입니다. 마지막 줄에.)
누구든지 쉘 1 라이너를 통해이 두 값을 추출하거나 어떻게 접근 해야하는지에 대한 힌트를 제공 할 수 있습니까?
해결책
grep -A 5 FAILED log.txt | \ # Get FAILED and dst and other lines
egrep '(FAILED|dst=)' | \ # Just the FAILED/dst lines
egrep -o "err:[0-9]*|dst=[0-9]*" | \ # Just the err: and dst= phrases
cut -d':' -f 2 | \ # Strip "err:" from err: lines
cut -d '=' -f 2 | \ # Strip "dst=" from dst= lines
xargs -n 2 # Combine pairs of numbers
023 447872123456
024 447872987654
모든 쉘 "One"-라이너와 마찬가지로,이를 수행하는 더 우아한 방법이 있습니다. 그러나, 나는 내가 원하는 것을 얻는 데 반복적 인 접근법이 매우 성공적으로 발견된다 : 너무 많은 정보 (당신의 grep)로 시작한 다음 내가 원하는 줄을 좁히고 (Grep과 함께) 내가 원하는 각 줄의 부분을 깎아 내린다. 자르다).
Linux Toolbox를 사용하면 더 많은 라인이 필요하지만 원하는 모든 명령의 기본 사항 만 알아야합니다. 대안은 AWK, Python 또는 기타 스크립팅 언어를 사용하는 것이 더 전문화 된 프로그래밍 지식이 필요하지만 화면 공간을 덜 취할 것입니다.
다른 팁
루비의 간단한 솔루션입니다 filter.rb
:
#! /usr/bin/env ruby
File.read(ARGV.first).scan(/:FAILED\s+err:(\d+).*?, dst=(\d+),/m).each do |err, dst|
puts "#{err} #{dst}"
end
다음과 같이 실행하십시오.
ruby filter.rb my_log_file.txt
그리고 당신은 얻는다 :
023 447872123456
024 447872987654
항상 같은 수의 필드가 있다면
grep -A5 "FAILED" log.txt | awk '$24~/err/ {print $24} $12~/dst/{print $12}' error.txt
err:023
dst=447872123456,
err:024
dst=447872987654,
그리고 나머지 파일 모양에 따라 모든 grep을 건너 뛸 수 있습니다.
"$ 24 ~/ err/ {print $ 24}"부품은 err, ~/ xxx/ xxx가 정규 표현식 인 경우 필드 번호 24를 인쇄하라고 말합니다.