bashスクリプトのカールから返されたXMLの解析

bashスクリプトのカールから返されたXMLの解析

私は過去数日間stackexchangeを見て達成したいいくつかのことを見つけましたが、それらをどのようにまとめるのかわかりません...

APIのカール呼び出しを作成するスクリプトを作成しようとしています。これにより、特定の値でのみ構文解析したいXMLバンドルが返されます。全体的に、私はこのスクリプトが呼び出しを行い、値を解析して変数に設定してから返す(表示)したいと思います。

ワークソリューションを見つけたかもしれませんが、それは実用的ですか?

#!/bin/bash

test=$(curl -k --silent "https://username:[email protected]?.full=true&name=devicename")
test2=$(curl -k --silent "https://username:[email protected]?.devicestatus&name=devicename")

variable1=$grep -oPm1 "(?<=<name>)[^<]+" <<< "$test:)
variable2=$grep -oPm1 "(?<=<status>)[^<]+" <<< "$test:)

echo "$variable"
echo "$variable2"

[admin]>./script SwitchName UP

これは私が採掘したいXMLです。

<?xml version="1.0" ?>
<queryResponse type="AccessPointDetails" rootUrl="https://website/webacs/api/v1/data" requestUrl="https://website/webacs/api/v1/data/AccessPointDetails?.full=true&amp;name=devicename" responseType="listEntityInstances" count="1" first="0" last="0">
  <entity url="https://website/webacs/api/v1/data/AccessPointDetails/14008947223" type="AccessPointDetails" dtoType="accessPointDetailsDTO">
    <accessPointDetailsDTO id="14008947223" displayName="14008947223">
      <clientCount>6</clientCount>
      <clientCount_2_4GHz>0</clientCount_2_4GHz>
      <clientCount_5GHz>6</clientCount_5GHz>
      <ipAddress>172.16.83.5</ipAddress>
      <name>devicename</name>
      <unifiedApInfo>
        ......
      </unifiedApInfo>
      <upTime>609857</upTime>
    </accessPointDetailsDTO>
  </entity>
</queryResponse>

<?xml version="1.0" ?>
<queryResponse type="AccessPointDetails" rootUrl="https://website/webacs/api/v1/data" requestUrl="https://website/webacs/api/v1/data/AccessPointDetails?.full=true&amp;name=devicename" responseType="listEntityInstances" count="1" first="0" last="0">
  <entity url="https://website/webacs/api/v1/data/AccessPointDetails/14008947223" type="AccessPointDetails" dtoType="accessPointDetailsDTO">
    <accessPointDetailsDTO id="14008947223" displayName="14008947223">
      <name>devicename</name>
      <status>UP</status>
      <unifiedApInfo>
        ......
      </unifiedApInfo>
    </accessPointDetailsDTO>
  </entity>
</queryResponse>

ベストアンサー1

まず、あなたの考えを変えるのに役立ついくつかのコメント/質問:

(つまり、コメントから始めて実際の答えに変わったことになります。)

  1. すでに知っている要素を抽出しようとしているのはなぜですか? (URLdevicenameから)XMLを取得するために使用する要素は何ですか?name=devicename

  2. まだなくても、2番目のcurlコマンド(?.devicestatus)には要素devicenamestatus要素が含まれているので、2番目のコマンドを取得するだけです。

  3. あなたvariable1=variable2=ラインが真剣に混乱しています。両方の行にnotを使用し、$grep別の二重引用符の代わりに二重引用符を使用して$(grep二重引用符を終了しました。:

    <<< "$test"つまり、代わりにこのように見えるはずです<<< "$test:

  4. 他の人がすでにコメントで述べたように、正規表現を使用してXMLを解析することは実際には良いアプローチではありません。xmlstarletたとえば、シェルスクリプトでXMLを処理するのに役立つツールであるXMLプロセッサを代わりに使用します。または、言語(たとえばperlpython利用可能なXML処理ライブラリを含む言語)でスクリプトを作成します。このサイトを検索してhttps://stackoverflow.com/多くの例)。

  5. 上記の3.と4.のため、あなたの質問に対する答えは「いいえ、まったく機能せず、ここで正規表現を使用してはいけないので実用的ではありません」です。

今、いくつかの可能な解決策は次のとおりです。

これにより、スクリプトの構文エラーを修正して実行することができます。

#!/bin/bash

test=$(curl -k --silent "https://username:[email protected]?.full=true&name=devicename")
test2=$(curl -k --silent "https://username:[email protected]?.devicestatus&name=devicename")

variable1=$(grep -oPm1 "(?<=<name>)[^<]+" <<< "$test1")
variable2=$(grep -oPm1 "(?<=<status>)[^<]+" <<< "$test2")

echo "$variable"
echo "$variable2"

しかし、これは特に正規表現がXMLを安定して解析できないため、最適とは離れています。これを試すことは、せいぜい醜いハッキングであり、条件(XML入力など)が抽出したいものに完全に完全である場合にのみ機能します。サーバーからXML出力を少し変更しても(改行を含む余分なスペースを削除するなど)、スクリプトが破損する可能性があります。

私があなたがやっていることをやろうとしたら、おおよそ次のようにします。

#!/bin/bash

U='username'
P='password'
site='website.api.address'

element_base='queryResponse/entity'
element_AP="${element_base}/accessPointDetailsDTO"
element_status="${element_AP}/status"

devname='devicename'

url="https://${U}:${P}@${site}?.devicestatus&name=${devname}"

xml=$(curl -k --silent "$url")

status=$(printf '%s\n' "$xml" | xmlstarlet sel -t -v "$element_status")

echo "$devname: $status"

このようにスクリプトを作成する際に役立つ1つは、さまざまな変数からさまざまな文字列($url特に$element_status)を作成することで、誤字やその他のエラーの危険なしに簡単に変更できることです。コマンドライン(たとえば、コマンドラインオプションの処理などU="$1" ; P="$2" ; devname="$3")、設定ファイル、またはその両方からインポートすることもできます。コマンドラインに複数を提供してループにインポートすることもできます。getopts-u username -p passsword -d devicenamedevname

以下は、これらのアイデアのいくつかを組み合わせた別のバージョンのスクリプトです。

#!/bin/bash

# get username and password, and remove them from the args
U="$1" ; shift
P="$1" ; shift #edited. was $2

site='website.api.address'

element_base='queryResponse/entity'
element_AP="${element_base}/accessPointDetailsDTO"
element_status="${element_AP}/status"

url="https://${U}:${P}@${site}?.devicestatus"

for devname in "$@" ; do

  xml=$(curl -k --silent "${url}&name=${devname}")

  status=$(printf '%s\n' "$xml" | xmlstarlet sel -t -v "$element_status")

  echo "$devname: $status"
done

おすすめ記事