如何查找字符串的第二个出现位置,然后删除该出现位置下面两行

时间:2019-06-20 19:19:20

标签: perl awk sed

我有一个xml文件,我想找到第二次出现的字符串,然后从字符串中删除第二行。这是外观的示例:

<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>

参数标记应从第二个实例中完全删除

我正在搜索tester.update,然后尝试删除第二次出现tester.update时向下两行的行

我尝试做类似的事情:

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

但这会从tester.update.的两个实例中删除第二行

非常感谢您提前提供帮助

3 个答案:

答案 0 :(得分:1)

使用XML解析器,Perl解决方案会简单得多。这是Mojo::DOM的样子,它使用CSS rules查找标签:

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>缺少的结束标记)

答案 1 :(得分:0)

这可能对您有用(GNU sed):

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

每次看到字符串tester.update时,请在保持空间中增加一个计数器。如果该计数器包含2,请交换回当前行,将其打印出来并显示下一行,然后删除下一行。

答案 2 :(得分:0)

假设您没有XML解析器:

sed用于在单独的行上进行s / old / new,仅此。对于其他任何事情,您都应该使用awk,例如在每个UNIX盒子上的任何外壳中的任何awk中,您都可以清楚而简单地执行以下操作:

$ 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>

是否要找到tester.update的第127次而不是第二次?只需将cnt==2更改为cnt==127。想要删除找到的第93行而不是第2行吗?只需将skip=NR+2更改为skip=NR+93。尝试对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>

但重要的是您不必,最后,如果您喜欢使用-i就地编辑GNU sed,则GNU awk与-i inplace相同。 / p>

相关问题