如何从shell脚本中的标签中删除一行?

如何从shell脚本中的标签中删除一行?

我们有一个 xml 文件(abc_lop.xml),我需要删除其中标签中存在的一行:

下面是一个 xml 文件,我已将其缩短,因为它很大。

<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">


    <!-- some data here  -->

</HELLO>

正如你所看到的,我在上面的标签xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd"中有这一行。HELLO我需要删除这条线并保留其他东西。

截至目前,我正在向上面的 xml 文件添加一些页眉和页脚,如下所示在我的 shell 脚本中,然后将其存储在文件变量中: Here $wordis abc.

file=$(printf '%s\n%s\n%s' "$header" "$(cat "$path/${word}_lop.xml")" "$footer")

现在我想确保文件变量应该具有 xml 文件数据,但也从HELLO标记中删除该行。

我稍后会将此$file变量用于其他目的,因此我想确保$file也应删除页眉、页脚和该行。具有 key=value 对的行只会出现一次。

答案1

请不要使用正则表达式来修改 XML。 XML 规范允许一些与基于正则表达式的解析无法很好地配合的事情。

这是一个非常糟糕的主意,因为你创建了脆弱的代码。有一天,您正在使用的源 XML 可能会更改为其他完全有效的内容(就 XML 规范而言),并且您的下游修改脚本将会中断。

这正是让系统管理员和维护程序员非常悲伤的事情。

请使用 XML 解析器。xmlstarlet是一种选择。两者perlpython都有解析选项。这两件事都处理 XML 中的奇怪情况(例如换行、漂亮的打印等)并确保下游 XML 有效 - 输出有效的 XML 很重要,因为无效的 XML应该成为致命的状况。

具体来说 - 从HELLO元素中删除一个属性:

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig -> new ( 'pretty_print' => 'indented_a' ) -> parse ( \*DATA );

foreach my $hello ( $twig -> findnodes ('//HELLO') ) {
    $hello -> del_att('xmlns:xsi');
}
$twig -> print;

__DATA__
<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">


    <!-- some data here  -->

</HELLO>

注意 - 我已经“漂亮地打印”了结果:

<HELLO
    version="4.2"
    xmlns="http://www.bacd.org/HELLO-4_2"
    xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">
    <!-- some data here  -->
</HELLO>

给我们一个例子来说明为什么基于正则表达式的解析是一个坏主意 - 因为那是有效的 XML。

也是如此:

<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">
    <!-- some data here  -->
</HELLO>

和:

<HELLO
version="4.2"
xmlns="http://www.bacd.org/HELLO-4_2"
xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd"
>
    <!-- some data here  -->
</HELLO>

和:

<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd"><!-- some data here  --></HELLO>

但 XML 解析器既简单又好用。

要将代码简化为像 sed 这样的单行代码:

perl -0777 -MXML::Twig -e 'XML::Twig -> new ( pretty_print => "indented_a", twig_handlers => { "HELLO" => sub { $_ -> del_att("xmlns:xsi") }} ) -> parse ( <> ) -> print;'

如果通过 STDIN 或通过指定文件名提供数据,应该可以工作。

答案2

要删除该xsi:schemaLocation条目,并保持文件的其余部分不变:

$ sed 's/xsi:schemaLocation="[^"]*"//' "$path/${word}_lop.xml"
<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >


    <!-- some data here  -->

</HELLO>

s/xsi:schemaLocation="[^"]*"//是一个替代命令。它将任何xsi:schemaLocation="[^"]*"与正则表达式匹配的内容替换为空。

要将其与您的脚本结合起来:

file=$(printf '%s\n%s\n%s' "$header" "$(sed 's/xsi:schemaLocation="[^"]*"//' "$path/${word}_lop.xml")" "$footer")

相关内容