см. https://stackoverflow.com/questions/5858200/sed-replace-every-nth-occurrence
Решение использует awk, а не sed, но "используют правильный инструмент для задания". Это может или не может быть возможно сделать в sed, но, даже если это будет, то это будет намного легче в инструменте как awk или жемчуг.
Как насчет этого:
while read number;do
start=$(grep "Processing Batch /fbc/dev/cebi/dod/$number" log_file\
|head -n 1|awk '{print $2}')
end=$(grep -A 1 "Batch $number was successful" log_file\
|head -n 2|tail -n 1|awk -v OFS=',' '{print $2,$6}')
echo "$number,$start,$end Secs"
done <cust_no.txt
Если Вы не возражаете использовать Perl, и grep здесь является решением Вашей проблемы. Вот сценарий, названный cmd.pl
:
#!/usr/bin/env perl
use feature 'say';
#use Data::Dumper;
@file = `grep -f cust_no.txt -A 1 sample.log`;
my (%info, $secLineSeen, $time, $custno);
$secLineSeen = 0;
foreach my $line (@file) {
if ($secLineSeen == 1) {
#2013/09/05 08:18:18 Total Time = 8.27 Secs
(my $totTime) = ($line =~ m!\S+ \S+\s+Total Time\s+=\s+(\S+ Secs)!);
$info{$custno}{totTime} = $totTime;
$secLineSeen = 0;
} elsif ($line =~ m/Processing Batch/) {
#2013/09/05 08:18:10 Processing Batch /fbc/dev/cebi/dod/9844867675
($time, $custno) = ($line =~ m!\S+ (\S+)\s+Processing Batch.*/(\S+)!);
$info{$custno}{onetwo} = $time;
} elsif ($line =~ m/Batch.*successful/) {
#2013/09/05 08:18:18 Batch 9886743777 was successful
($time, $custno) = ($line =~ m!\S+ (\S+)\s+Batch (\S+) was.*!);
$info{$custno}{twotwo} = $time;
$secLineSeen = 1;
}
}
#print Dumper(\%info);
#9739867262,04:26:00,04:26:02,3.13 Secs
foreach my $key (sort keys %info) {
say "$key,$info{$key}{onetwo},$info{$key}{twotwo},$info{$key}{totTime}";
}
$ ./cmd.pl
9739867262,04:26:00,04:26:02,3.13 Secs
9844867675,08:18:10,08:18:16,6.00 Secs
9886743777,08:18:10,08:18:18,8.27 Secs
Этот сценарий Perl сначала создает массив, @file
, который содержит результаты этой команды:
$ grep -f cust_no.txt -A 1 sample.log
Эта команда берет файл журнала, sample.log
, и выбирает все строки, которые содержат клиентские числа из файла cust_no.txt
, как так:
2013/09/05 04:26:00 Processing Batch /fbc/dev/cebi/dod/9739867262
2013/09/05 04:26:02 Batch 9739867262 was successful
2013/09/05 04:26:02 Total Time = 3.13 Secs
--
2013/09/05 08:18:10 Processing Batch /fbc/dev/cebi/dod/9844867675
2013/09/05 08:18:10 Processing Batch /fbc/dev/cebi/dod/9886743777
2013/09/05 08:18:16 Batch 9844867675 was successful
2013/09/05 08:18:16 Total Time = 6.00 Secs
--
2013/09/05 08:18:18 Batch 9886743777 was successful
2013/09/05 08:18:18 Total Time = 8.27 Secs
Это grep
команда делает одну дополнительную специальную вещь, которую стоит упомянуть, главным образом что это сохраняет одну дополнительную строку после (-A 1
) любое соответствие. Это позволяет нам захватывать строку с "Общим временем" в нем.
После того как эти данные были извлечены, сценарий Perl затем использует многомерный хеш для хранения результатов основных частей данных из этого вывода согласно требованиям, упомянутым в вопросе.
Хеш похож на это, после того как мы завершили обработку содержания @file
:
$VAR1 = {
'9739867262' => {
'twotwo' => '04:26:02',
'totTime' => '3.13 Secs',
'onetwo' => '04:26:00'
},
'9886743777' => {
'twotwo' => '08:18:18',
'totTime' => '8.27 Secs',
'onetwo' => '08:18:10'
},
'9844867675' => {
'twotwo' => '08:18:16',
'totTime' => '6.00 Secs',
'onetwo' => '08:18:10'
}
};
Наконец мы циклично выполняемся через этот хеш и печатаем содержание, которое мы собрали в формате, указанном в вопросе.
Я попробовал бы grep на этом:
grep -EA 1 'pattern1|pattern2' file.log
Используйте опцию-E для расширенного regex и-A для количества строк для следования за соответствием. Теперь для получения распечатанного на одной строке я могу думать о той очень hackish способ использовать sed:
grep -EA 1 'pattern1|pattern2' file.log | grep -v ^-- | sed 'N ; s+\n+|+g'
Передача команды N
(считайте следующую строку) к sed позволяет Вам обрабатывать две строки входа за один раз. С другой стороны, команда s+\n+|+g
позволяет Вам заменять (символом делителя своего выбора) или удалять (если замена пуста), новая строка между этими двумя обрабатываемыми строками, оставляя только новую строку в конце второй строки.
grep -v ^--
необходимо, чтобы я избавился от --
произведенный первым grep экземпляром (см. иллюстративный пример ниже).
Line 1
Line 2
--
Line X
Line Y