Сценарий оболочки / регулярное выражение: извлечение через несколько строк
Вопрос
Я пытаюсь написать сценарий анализа журнала для извлечения сбойных событий. Я могу вытащить их с помощью 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" часть ": FAILED err: 023" в первой строке) и номер dst (то есть "447872123456"); из "dst = 447872123456" в последней строке.)
Может ли кто-нибудь помочь с однострочником оболочки для извлечения этих двух значений или дать несколько советов относительно того, как мне следует подходить к этому?
Решение
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 занимает больше строк, вам нужно знать только основы нескольких команд, чтобы делать практически все, что вы хотите. Альтернативой является использование awk, python или других языков сценариев, которые требуют более специализированных знаний программирования, но занимают меньше места на экране.
Другие советы
Простое решение в Ruby, вот 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 all вместе.
" $ 24 ~ / err / {print $ 24} " part указывает awk напечатать поле с номером 24, если оно содержит ошибку, ~ / XXX /, где XXX - регулярное выражение.