найти номер строки последнего вхождения шаблона перед конкретным номером строки - PullRequest
1 голос
/ 18 мая 2011

У меня есть большой файл событий, например:

<event>
...
...multiple lines describing the event
...
</event>
<event>
...
... 
<event>

При возникновении ошибки я получаю номер строки, где произошла ошибка, которая всегда заканчивается где-то внутри тегов событий.Я хочу разбить файл на события, обработанные до возникновения ошибки и начиная с нее.Я знаю, что я могу сделать разделение, используя

csplit -k filename line_number_to_split_on

Что мне нужно сделать, это найти номер строки предыдущего тега события в строке ошибки.Файлы довольно большие.Например, у меня есть ошибка, указанная в строке 1007425, и при просмотре файла тег события находился в строке 1007397. Я хотел бы сделать это в сценарии оболочки.Есть идеи?

Ответы [ 3 ]

2 голосов
/ 19 мая 2011

Учитывая $ LINE в качестве номера строки, в которой возникает ошибка, и $ FILE в качестве входного файла, вы можете сделать:

$ nl -ba $FILE | sed -n -e '/<event>/p' -e ${LINE}q | tail -1

(Вы можете использовать оператор '=' в sed для получения строкичисла вместо nl, но мне больше нравится nl и = не очень переносимо. Кроме того, он добавляет дополнительные новые строки, которые немного болезненны.)

В качестве альтернативы конвейерной обработке вы можете сделать следующее:

$ nl -ba $FILE | sed -n -e '/<event>/h' -e$LINE'{x; p; q;}'
1 голос
/ 18 мая 2011

Я не уверен в производительности больших файлов, но она работает.

#!/bin/sh
total=$(cat EVENTFILE |wc -l)
error=$1 ### Line number where error occurred
from=$((total-error))
num=$(tac EVENTFILE|awk '/<event>/{print NR}'|while read n; do
    echo ${n};
    if test ${n} -ge ${from}; then
        break;
    fi;
    done|tail -1)
echo $((total-num+1))

Данные испытаний.

 1  <event>
 2  .
 3  .
 4  .
 5  </event>
 6  <event>
 7  ..
 8  ..
 9  ..
10  </event>
11  <event>
12  ...
13  ...
14  ...
15  </event>

выход

foo@ell:/tmp/test$ ./test.sh 3
1
foo@ell:/tmp/test$ ./test.sh 8
6
foo@ell:/tmp/test$ ./test.sh 14
11
1 голос
/ 18 мая 2011

Ваш ввод выглядит как XML. Лучший способ сделать это - использовать синтаксический анализатор XML. Парсинг XML вручную не так уж и интересен. В зависимости от XML-парсера номера стартовой строки являются частью метаданных элемента. (Например, для SAX есть Locator .)

Обновление:

Считалось, что использование правильного инструмента - хорошая идея. Если вы не можете использовать синтаксический анализатор XML, вы должны написать свой собственный для своего подмножества XML. Вам следует начать с изучения стандарта XML и посмотреть, какие функции вам действительно нужны. Это избавило бы вас от многих сложностей, если бы вам не приходилось поддерживать рекурсию, объекты XML и XML CDATA. После получения этой информации на ваш вопрос можно ответить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...