シェルスクリプトのタグから1行を削除する方法は?

シェルスクリプトのタグから1行を削除する方法は?

(abc_lop.xml)タグに存在する行を削除する必要がある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ファイルにヘッダーとフッターを追加し、ファイル変数に保存してい$wordますabc

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

HELLOこれで、ファイル変数にxmlファイルデータが必要ですが、タグからその行も削除する必要があることを確認したいと思います。

この変数は後で他の目的に使用する予定なので、ヘッダー、フッター、行も一緒に削除する必要があるかどうかを$file確認したいと思います。$fileキーと値のペアを持つ行は一度だけ表示されます。

答え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などの1行のコードに減らすには:

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

関連情報