Обратный поиск шаблона от Specifi c Линия в Bash - PullRequest
0 голосов
/ 28 февраля 2020

Скажем, у меня большой XML словарь, отформатированный примерно так:

<entry>
<!-- arbitrary amount of lines -->
<head>SomeWord</head>
<!-- arbitrary amount of lines -->
</entry>

И предположим, я знаю, что SomeWord находится на линии 3026138. Я хотел бы выполнить поиск в обратном направлении от строки 3 026 138 до <entry>, но я не знаю, сколько строк находится между <entry> и моей целевой линией.

Этот ответ работает правильно, если я использую номер строки, а не шаблон, как показано ниже

sed '/<entry>/h;//!H;3026138!d;x;q' file

Однако это несколько неоптимальное решение, так как я думаю, sed сканирует строку 0 и сканирует файл в течение 3 миллион строк. Это кажется расточительным, так как я уже знаю, в какой области файла я хочу работать. В общем, это занимает около полсекунды.

У кого-нибудь есть решение, которое использует тот факт, что я в курсе номера строки, который использует обычные программы Unix / sh, которые есть у всех (например, grep, awk, sed и т. д.)?

Примечание: пожалуйста, не предлагайте использовать что-то вроде xmllint. Он не только очень медленный, но я также хотел бы, чтобы это был сценарий метаформатности c.

Ответы [ 2 ]

1 голос
/ 29 февраля 2020

Проблема с такими инструментами, как sed, заключается в том, что они обрабатывают строку в тот момент, когда вы хотите обработать большую часть файла в целом. Введите ed. Следующая строка печатает все между первой строкой с <entry>, найденной перед строкой 3026138, до этой строки:

echo "3026138;?<entry>?,.p" | ed -s file

(Устанавливает текущую строку в строку 3026138, печатает диапазон между первым совпадением <entry> до текущая строка в текущую строку. Если вы хотите сохранить чанк в другом файле, вы можете использовать w foo.txt вместо p).

Пример использования файла примера и строки 3:

$ echo "3;?<entry>?,.p" | ed -s input.txt
<entry>
<!-- arbitrary amount of lines -->
<head>SomeWord</head>
0 голосов
/ 28 февраля 2020

Здесь я попытался сделать следующее:

  1. Сохранить запись номеров строк тегов в отдельный файл
  2. , указав желаемый номер строки заголовок tag
  3. , выполняющий поиск " где он подходит "

Входной файл:

someline
someline
<entry>
someline
someline
<head>Here</head>
someline
</entry>
someline
<entry>
someline
<head>Another</head>
someline
someline
someline
</entry>
someline
someline

сценарий оболочки (может быть разделен на выполнить поиск по заданному ($ 1) номеру строки. Чтобы выполнить несколько операций поиска в файле или использовать его различными способами (получение нужного тега с помощью различных подходов, а затем предоставление номера строки сценарию поиска для выполнения поиска)

# preparation before doing searches
 ln=12 # line number with desired <head>
 cat input.txt | sed '$a<entry>' | grep -n '^<entry>' | cut -d ':' -f1 > entryl.txt
# doing searches
 t=0
 for x in $(seq $(cat entryl.txt | wc -l)); do
  c=$(cat entryl.txt | head -n $x | tail -n 1)
  if test $t -eq 1; then
   if test $ln -lt $c; then
    echo "<head> tag on line: $ln"
    echo "Previous <entry> found at: $p"
    echo "Next <entry> found at: $c"
    break;
   else
    p=$c
   fi
  else
   if test $ln -gt $c; then
    p=$c; t=1
   fi
  fi
 done

Пример вывода:

<head> tag on line: 12
Previous <entry> found at: 10
Next <entry> found at: 19
...