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. 이미 알고 있는 요소를 추출하려고 하는 이유는 무엇입니까 ? ( URL devicename에서) XML을 가져오는 데 사용하는 요소는 무엇입니까 ?name=devicename

  2. 아직 없어도 두 번째 curl명령( ?.devicestatus)에는 devicenamestatus요소가 포함되어 있으므로 두 번째 명령만 얻으면 됩니다.

  3. 당신 variable1=variable2=라인이 심각하게 엉망입니다. 두 줄 모두에 not을 사용했으며 $grep다른 큰따옴표 대신 큰따옴표 하나로 $(grep큰따옴표를 종료했습니다 .:

    <<< "$test"즉, 대신에 이렇게 보여야 합니다<<< "$test:

  4. 다른 사람들이 이미 주석에서 언급했듯이 정규식을 사용하여 XML을 구문 분석하는 것은 실제로 좋은 접근 방식이 아닙니다. xmlstarlet예를 들어, 쉘 스크립트에서 XML을 처리하는 데 유용한 도구인 XML 프로세서를 대신 사용하십시오 . 또는 언어(예 perl: python사용 가능한 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"

이러한 방식으로 스크립트를 작성할 때 유용한 점 중 하나는 다른 변수에서 다양한 문자열( $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

관련 정보