Analisar xml retornado do curl dentro de um script bash

0

Eu tenho pesquisado através do stackexchange nos últimos dias e descobri fragmentos do que estou tentando realizar, mas não tenho certeza de como juntar tudo ...

Estou tentando criar um script que tenha chamadas curl para uma API. Isso retorna um monte de xml que eu quero, em seguida, analisar apenas alguns valores apenas. No geral, quero que esse script faça a chamada, analise os valores / defina-os como uma variável e retorne (exiba) eles.

Eu posso ter encontrado uma solução de tipo de trabalho, mas isso é prático?

#!/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

Aqui está o XML que estou tentando analisar:

<?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>
    
por Ryan 20.04.2016 / 18:19

1 resposta

2

Primeiro, alguns comentários / perguntas para você pensar de uma maneira diferente:

(em outras palavras, isso começou como um comentário, mas se tornou uma resposta real em algum lugar ao longo do caminho)

  1. Por que você está tentando extrair o elemento devicename quando já o conhece - é o que você usou para buscar o XML (com name=devicename na URL)?

  2. Mesmo se você ainda não o tiver, o segundo comando curl (com ?.devicestatus ) contém os elementos devicename e status , portanto, você só precisa buscar o segundo.

  3. Suas linhas variable1= e variable2= estão seriamente confusas. você usou $grep em vez de $(grep nas duas linhas e finalizou a aspa dupla com : em vez de outras aspas duplas.

    i.e. deveria ser como <<< "$test" , não <<< "$test:

  4. Como outros já mencionaram nos comentários, usar expressões regulares para analisar XML não é uma boa maneira de fazer isso. Use um processador XML, por ex. xmlstarlet é uma ferramenta útil para trabalhar com XML em scripts de shell. Ou escreva seu script em um idioma (por exemplo, perl ou python que tem bibliotecas de processamento XML disponíveis. Pesquise aqui neste site e no link para muitos exemplos).

  5. Por causa de 3. e 4. acima, a resposta à sua pergunta é "Não, isso não é prático porque não funciona e porque expressões regulares não devem ser usadas aqui". / p>

Agora, para algumas soluções possíveis:

Isso apenas corrige os erros de sintaxe em seu script para que ele seja executado:

#!/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"

Isso está longe de ser ideal, embora as expressões regulares não possam analisar de maneira confiável o XML. Tentar fazê-lo é, na melhor das hipóteses, um truque feio e só funciona se as condições (ou seja, a entrada XML) forem absolutamente perfeitas para o que você está tentando extrair. Mesmo pequenas alterações na saída XML pelo servidor (como a eliminação de espaços em excesso, incluindo novas linhas) podem e irão quebrar seu script.

Se eu estivesse tentando fazer o que você parece estar fazendo, é mais ou menos assim:

#!/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"

Uma das coisas úteis sobre como escrever o script dessa maneira é que, construindo as várias strings ( $url e $element_status em particular) de outras variáveis, é fácil alterá-las sem muito risco de erros de digitação ou outros erros. . Eles também podem vir da linha de comando (por exemplo, U="$1" ; P="$2" ; devname="$3" ou usando getopts para processar opções de linha de comando como -u username -p passsword -d devicename ) ou de um arquivo de configuração, ou ambos. Você também pode fornecer vários devname s na linha de comando e buscá-los em um loop.

Aqui está outra versão do script que combina algumas dessas ideias:

#!/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
    
por 21.04.2016 / 11:51