Как найти 2-й вхождение строки, а затем удалить строку на 2 строки ниже этого вхождения - PullRequest
0 голосов
/ 20 июня 2019

У меня есть XML-файл, в котором я хотел бы найти второе вхождение строки, а затем удалить строку на 2 строки вниз от строки. Вот пример того, как это выглядит:

<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
            <argument>READ_ONLY</argument>
       </const>
       <role>sysad</role>
</application>

<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
             <argument>READ_ONLY</argument>
       </const>
       <role>tester</role>
</application>

Вот как я хочу, чтобы это выглядело:

<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
            <argument>READ_ONLY</argument>
       </const>
       <role>sysad</role>
</application>
.
.
.
<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
       </const>
       <role>tester</role>
</application>

Теги аргументов должны быть полностью удалены из 2-го экземпляра

Я ищу tester.update, а затем пытаюсь удалить строку, которая на 2 строки ниже, во втором появлении tester.update

Я пытался сделать что-то вроде:

sed -i 'tester.update/{p;N;d}' file.txt 

но это удаляет 2-ю строку из обоих экземпляров tester.update.

Спасибо за любую помощь заранее

Ответы [ 3 ]

1 голос
/ 20 июня 2019

Решение Perl было бы намного проще с парсером XML.Вот как это может выглядеть с Mojo :: DOM , который находит теги, используя правила CSS :

use strict;
use warnings;
use Mojo::DOM;
use open ':std', ':encoding(UTF-8)';

my $xml = do { local $/; <> };
my $dom = Mojo::DOM->new->xml(1)->parse($xml);
$dom->at('application:nth-of-type(2) > app > const')->content('');
print $dom->to_string;

Результаты:

<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
            <argument>READ_ONLY</argument>
       </const>
       <role>sysad</role>
</app></application>

<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const />
       <role>tester</role>
</app></application>

(он даже исправил отсутствующий тег закрытия для <app>)

0 голосов
/ 21 июня 2019

Если у вас нет синтаксического анализатора XML:

sed предназначен для выполнения s / old / new в отдельных строках, это все . Для всего остального вы должны использовать awk, например с любым awk в любой оболочке на каждом компьютере UNIX вы можете просто и просто сделать:

$ awk '/tester.update/{if (++cnt==2) skip=NR+2} NR!=skip' file
<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
            <argument>READ_ONLY</argument>
       </const>
       <role>sysad</role>
</application>

<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
       </const>
       <role>tester</role>
</application>

Хотите найти 127-е вхождение tester.update вместо 2-го? Просто измените cnt==2 на cnt==127. Хотите удалить 93-ю строку после того, как она найдена вместо 2-й? Просто измените skip=NR+2 на skip=NR+93. Попробуйте внести такие простые изменения (или что-нибудь еще!) В решение sed.

Как sed для краткости? Вы также можете пожертвовать ясностью ради краткости в awk:

$ awk '/tester.update/&&++c==2{s=NR+2}NR!=s' file
<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
            <argument>READ_ONLY</argument>
       </const>
       <role>sysad</role>
</application>

<application>
    <app>
       <Name>Tester</Name>
       <Class>tester.update</Class>
       <const>
       </const>
       <role>tester</role>
</application>

но важно вам не нужно и, наконец, если вам нравится GNU sed для редактирования на месте с помощью -i, GNU awk имеет то же самое с -i inplace.

0 голосов
/ 21 июня 2019

Это может работать для вас (GNU sed):

sed -Ei '/tester.update/{x;s/^/x/;/^x{2}$/{;x;n;n;d};x}' file

Каждый раз, когда отображается строка tester.update, увеличивайте счетчик в области удержания.Если этот счетчик содержит 2, вернитесь к текущей строке, напечатайте ее и следующую строку и удалите следующую.

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