У меня есть файл odt с пустыми строками между строками текста. Я хочу найти термин и вывести всю группу текста, где есть совпадение с термином. Мой подход заключается в том, чтобы сказать, что пустые строки в файле odt являются разделителями записей. Файлы odt - это zip-архивы с текстом, содержащимся в файле content.xml. После распаковки файла odt я использовал xmllint --format content.xml для вставки новых строк (как показано ниже), а "пустые" строки на самом деле являются строками без текста между > и <. Поэтому я хочу установить RS как любую такую строку, в которой нет текста между > и <. Если отформатированный файл content.xml выглядит следующим образом:
<long line of alphanumerics, slashes, single and double quotes><more or the same><and many more>
<office:text>
<text:sequence-decls>
<text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>
<text:sequence-decl text:display-outline-level="0" text:name="Table"/>
<text:sequence-decl text:display-outline-level="0" text:name="Text"/>
<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
<text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
</text:sequence-decls>
<text:p text:style-name="P1">This is the first line</text:p>
<text:p text:style-name="P1"/>
<text:p text:style-name="P1">This is the third line</text:p>
<text:p text:style-name="P1">and this is some more text that is to be included</text:p>
<text:p text:style-name="P1"/>
<text:p text:style-name="P1">This is the sixth. I want it included,</text:p>
<text:p text:style-name="P1">with this line</text:p>
<text:p text:style-name="P1">and this one</text:p>
</office:text>
и код выглядит следующим образом:
$ awk '/line/' RS='\n[ \t]*<[^>]*>\n' file.xml
Весь файл выводится. Но я хочу только:
<text:p text:style-name="P1">This is the first line</text:p>
<text:p text:style-name="P1">This is the third line</text:p>
<text:p text:style-name="P1">and this is some more text that is to be included</text:p>
<text:p text:style-name="P1">This is the sixth. I want it included,</text:p>
<text:p text:style-name="P1">with this line</text:p>
<text:p text:style-name="P1">and this one</text:p>
Отвечая на свой вопрос, вдохновленный steeldriver, я изменил файл перед использованием awk:
sed '/>.*</! s/.*/---/' test.txt > modfile.txt # overwrites lines matching the pattern with what I will name as the record separator, “---”
Затем я смог извлечь всю запись о совпадениях с $ searchterm
awk "/$searchterm/" RS="---" modfile.txt > results.txt
Ваш подход чреват проблемами. Что наиболее важно, нет очевидного способа ограничить соответствие регулярного выражения основным текстом документа - например, в случае / line /
, который будет соответствовать таким тегам, как
(Также существует проблема с вашим RS
регулярным выражением, использующим два символа новой строки, что помешает ему правильно обработка соседних разделителей; RS = '\ n ([\ t] * <[^>] *> \ n) +'
может исправить это, но я не гарантирую этого).
Вместо,я бы предложил сначала извлечь основной текст документа, а затем затем применить awk в "традиционном" режиме абзаца (т.е. с использованием пустого разделителя записей):
xmlstarlet sel -t -v "//office:body/office:text/text:p" -n content.xml |
awk -v RS= '/line/{print $0 ORS}'
или с помощью GNU awk, сохраняя фактические разделители записей как проанализировано:
xmlstarlet sel -t -v "//office:body/office:text/text:p" -n content.xml |
gawk -v RS= '/line/{printf $0 RT}'
Вы даже можете полностью опустить промежуточный файл, передав стандартный вывод из unzip -p
:
unzip -p somefile.odt content.xml |
xmlstarlet sel -t -v "//office:body/office:text/text:p" -n - | gawk -v RS= '/line/{printf $0 RT}'