xmlファイルをgrepし、結果に応じて出力をファイルにリダイレクトするスクリプト

xmlファイルをgrepし、結果に応じて出力をファイルにリダイレクトするスクリプト

だから私はXMLファイルを解析し、そのファイルの下にあるカテゴリ名に基づいて出力を新しいファイルにリダイレクトする簡単なスクリプトを書こうとしています。たとえば、XMLファイルは次のようになります。

<category> Music </Category>
<url>https://www.youtube.com/watch?v=waAlgFq9Xq8</url>
<category> Movies </Category>
<url>https://www.youtube.com/watch?v=g4U4BQW9OEk</url>

私のスクリプトは次のとおりです

for i in *.xml; do
    name=$(grep -i "<category>" $i | awk '{print $1}')
    line=$(grep -i -A1 "<category>" $i)
    echo "$line" >> $filename
done

たとえば、Movies.logには映画カテゴリ内のすべてのリンクが含まれ、Music.logには音楽カテゴリ内のすべてのリンクが含まれます。

答え1

各カテゴリを繰り返すことを検討しましたか?このように:

for i in *.xml; do
    for category in $(sed -rn '/^<category>/{s/[^>]*> *([^ <]*).*/\1/p}' "$i"); do
        sed -rn "/^<category> *$category/,/^<category>/{s/<url> *([^ <]*).*/\1/p}" "$i" > "$category.log"
    done
done

アップデート:awkを使う

awk -v 'RS=<' -v 'cat=none' -F '>' \
'$1 ~ /^category$/ {gsub(/^ *| *$/,"",$2); cat=$2} \
$1 ~ /^url$/ {print $2 >> cat".log"}' \
*.xml
  • これにより、入力ファイルが繰り返されるのを防ぎ、.logすべてのカテゴリのファイルに追加されます。

  • awkのレコード区切り記号割り当てを使用することは、-v 'RS=<'カテゴリ/ URLタグをどこでも(行の先頭だけでなく)見つけることができることを意味します。改行文字は xml データのどこにでも表示できます。

  • これをフィールド区切り文字の設定と組み合わせる'>'と、各レコードの最初のフィールドはxmlタグ名と同じになります。

  • awk は、最初のフィールドが「category」のレコードに会うたびに、cat変数をそのカテゴリの名前に設定します。

  • awkは、最初のフィールドが「url」のレコードを検出すると、そのURLをファイルに追加しますcat.log

  • catnone開始として定義されます。これにより、<url>前にaがない状況でエラーが発生するのを防ぎます<category>

  • 代替方法は、gsub(/^ *| *$/,"",$2)サンプル入力ファイルに表示されるカテゴリ名から先行/末尾のスペースを削除することです.xml


メモ:

上記のどれも完璧ではありません。正しい XML 入力ファイルの場合、実際の XML パーサーがより良いです。xmlstarlet。ただし、これには正しい形式のxmlファイルも必要です(<category>たとえば、入力例に一致するタグはありません)。

答え2

私は次のソリューションを準備しました。

grep -hP "<category.*>|<url.*>" *.xml | cut -d ">" -f 2 | cut -d "<" -f 1 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | gawk 'BEGIN { category = ""; } { if (!length($0)) { next; } if (length(category)) { printf("\necho -e \"%s\" >> \"%s.log\"", $0, category); category = ""; } else { category = $0; } } END { printf("\n"); }' | bash

現在のディレクトリ内のすべての.xmlファイルを検索し、追加URLの前の行にあるカテゴリ名にちなんで名前付きファイルのURL(末尾から| bashを削除して出力を確認できます)。

関心のあるデータに対してのみXMLノードを抽出します。

たとえば、grep を使用して、次の名前のファイルからパターンを検索します。*.xml、ファイル名を繰り返す必要はありません。オプション- 時間grepは出力でファイル名を抑制します。 grepで提供されるパターンはPerl互換正規表現(-血)

関心のあるノードの値を抽出します。

grepコマンドによって返される行は次のとおりです。

    <category> MyMusic </category>
    <url>https://www.youtube.com/watch?v=waAlgFq9Xq8123</url>
    <category> MyMovies </category>
    <url>https://www.youtube.com/watch?v=g4U4BQW9OEk456</url>
    <category>Music</category>
    <url>https://www.youtube.com/watch?v=waAlg</url>
    <category>              Music </category>
    <url>https://www.youtube.com/watch?v=waAlgFq9Xq8</url>
    <category> Movies </category>
    <url>https://www.youtube.com/watch?v=g4U4BQW9OEk</url>

不要なデータ行をフィルタリングしました。これで、ノード内の値を抽出する必要があります。これは、開始タグと終了タグの間のデータ、すなわちシンボル間のデータを抽出することで要約される。>そして<(私たちはそれがどのノードなのか気にしないので、「一般的な」方法を使います)。

これは簡単に達成できます。| cut -d ">" -f 2 | cut -d "<" -f 1

これは本質的にすべてを記号>(-f 2)の右側に持ち、次に私たちが得た新しい結果に従って記号<(-f 1)の左側にすべてをインポートすることを意味します。

これは私たちに次のような結果を残します。

 MyMusic 
https://www.youtube.com/watch?v=waAlgFq9Xq8123
 MyMovies 
https://www.youtube.com/watch?v=g4U4BQW9OEk456
Music
https://www.youtube.com/watch?v=waAlg
                Music 
https://www.youtube.com/watch?v=waAlgFq9Xq8
 Movies 
https://www.youtube.com/watch?v=g4U4BQW9OEk

これでこれらの値をクリーンアップする必要があります。ここに小さな修正ステップがあります。

トリム値

先行および末尾の空白の切り捨て| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

そして- 金利、sedは、追加のsedコマンド(または他の場合は複数のsedコマンド)をパイプすることなく、指定された順序でスクリプトを実行できます。

sedに渡された最初のスクリプトは先行スペース(つまり、文字列の先頭のすべての[:space:]文字(1行あたり))を切り捨て、2番目のスクリプトは末尾のスペース(つまり、最後の前のすべての[:space:]) )を切ります。 ]文字)文字列(@各行)。

これでこのようなものがあるので、ほぼ完了しました。

MyMusic
https://www.youtube.com/watch?v=waAlgFq9Xq8123
MyMovies
https://www.youtube.com/watch?v=g4U4BQW9OEk456
Music
https://www.youtube.com/watch?v=waAlg
Music
https://www.youtube.com/watch?v=waAlgFq9Xq8
Movies
https://www.youtube.com/watch?v=g4U4BQW9OEk

標準出力へのファイルの追加コマンドの書き込み

ファイルにデータを追加するためにechoコマンドを作成したのと同じように、プロセスを自動化できることが必要です。私はアイドル状態を選択します。 gawk はデータを 1 行ずつ読み込み、カテゴリを変数として取得します。別の行を読み取るときにカテゴリ変数が空でない場合、行にURLが含まれます。この手法により、echo -e "current url">>current_category.logなどのコマンドを簡単に実行できます。

気づく批判的>>を使用してファイルに新しいデータを追加します。 >を使用すると、最後のURLのみが作成され、カテゴリごとに1行ずつ表示されます。

その結果、標準出力に次のデータを書きました。

echo -e "https://www.youtube.com/watch?v=waAlgFq9Xq8123" >> "MyMusic.log"
echo -e "https://www.youtube.com/watch?v=g4U4BQW9OEk456" >> "MyMovies.log"
echo -e "https://www.youtube.com/watch?v=waAlg" >> "Music.log"
echo -e "https://www.youtube.com/watch?v=waAlgFq9Xq8" >> "Music.log"
echo -e "https://www.youtube.com/watch?v=g4U4BQW9OEk" >> "Movies.log"

bashの実行にデータを追加するコマンドを渡す

パイプラインの最後の要素は、| bashechoコマンドが実行のためにbashに渡されるようにします。

gawkはファイルにデータを書き込んだり追加したりできます。しかし、私は意図的に可能な最小のgawkスクリプトを持っていたかった。

関連情報