Bash를 사용하여 XML 데이터를 변수로 분할

Bash를 사용하여 XML 데이터를 변수로 분할

서비스에서 일부 파일을 다운로드하려고 합니다. 이러한 파일은 XML 파일에 있습니다. XML 파일에는 다운로드할 파일이 하나 이상 있을 수 있습니다. 그러나 이제 스크립트에 문제가 있습니다. 각 파일을 개별적으로 다운로드할 수 있도록 XMLLINT의 문자열을 배열로 분할하는 방법을 모르겠습니다.

문자열을 여러 변수로 분할한 다음 각 파일의 URL 문자열을 다운로드해야 합니다.

그런데 201701_1 파일은 중복되지 않아서 컬을 이용해 다운로드하는데 문제가 없습니다. 그런데 Coverage.zip 파일이 중복되어 컬로 가려져 있습니다. 나는 합니다: 그런 다음 컬을 사용하여 단일 파일을 다운로드합니다.

curl -O -b cookie $URL 

현재 내 스크립트는 다음과 같습니다.

while read edition; do   XML="<?xml version=\"1.0\"
encoding=\"UTF-8\"?> <download-area>   <files>
    <file>
      <url>https://google.com/411/201701_01_01.zip</url>
    </file>
    <file>
      <url>https://google.com/411/201701_01_02.zip</url>
    </file>   </files> </download-area>
    "
    URL=$(echo $XML | xmllint --xpath \
    "/*[name()='download-area']/*[name()='files']/*[name()='file']/*[name()='url']/text()" -)

    echo "URL:: " $URL

done < $LATEST_EDITION

LATEST_EDITION은 행을 포함하는 파일입니다.

제 질문은: VAR_1과 VAR_2를 여러 URL로 분할하여 개별적으로 다운로드하려면 어떻게 해야 합니까? Coverage.zip을 덮어쓰는 것을 방지하는 방법은 무엇입니까?

답변1

xmllintXML 문서에서 정보를 추출하는 것은 쓸모가 없습니다. xmlstarletor xml_grep(XML::Twig에서 perl) 또는 을 고려할 수 있습니다 xml2.

다음을 사용하여 xmllint한 번에 하나의 문자열을 추출할 수 있습니다 .

VAR1=$(printf '%s\n' "$XML" |
  xmllint --xpath '/download-area/files/file[1]/url/text()' -)
VAR2=$(printf '%s\n' "$XML" |
  xmllint --xpath '/download-area/files/file[2]/url/text()' -)

여기처럼 개행 문자를 포함하지 않는 값의 경우 bash's를 readarray다음과 같이 사용할 수 있습니다.

readarray -t var < <(
  xmlstarlet sel -t -v /download-area/files/file/url  <<< "$XML")

또는

readarray -t var < <(
  xml2 <<< "$XML" | sed -n 's|^/download-area/files/file/url=||p')

또는:

readarray -t var < <(
  xml_grep --text_only /download-area/files/file/url <<< "$URL")

답변2

다음과 같이 시도해 보세요:

declate -a url_array
url_array=(`echo $XML | grep -o "http.*zip" | tr '\n' ' '`)

답변3

xmllintXML을 분할하는 데는 좋은 도구가 아닙니다. 두 가지 문제(XML 구문 분석 및 고유 URL 보장)를 강력한 방식으로 해결하려면 다음을 사용 bash하십시오 xmlstarlet.

#!/bin/bash
XML='<?xml version="1.0" encoding="UTF-8"?>
<download-area>
  <files>
    <file>
      <url>https://google.com/411/201701_01_01.zip</url>
    </file>
    <file>
      <url>https://google.com/411/201701_01_02.zip</url>
    </file>
  </files>
</download-area>'

# IFS=$'\n'   ## required if URLs contains spaces
urls=( $(xml select -t -m  "/download-area/files/file" -v url -nl  <<< $XML ) )

declare -A unique  # associative array
for uu in ${urls[*]}; do let unique[$uu]++; done

for uu in "${!unique[@]}"; do
  printf "URL is %s\n" ${uu}
done

이는 템플릿( )이 xpath( )와 일치하고 노드의 값이 템플릿( )에서 선택되며 각 값( ) 뒤에 개행 문자가 추가되는 패턴 xmlstarlet에 사용 됩니다 . (xmlstarlet은 이보다 더 유연하므로 여러 번 사용할 수 있고 필요한 곳에 임의의 텍스트를 추가할 수 있습니다.)select-t-m-vurl-nl-v-o

또한 리디렉션을 사용하여 /pipe를 <<<저장합니다 echo.

URL은 일반 색인 배열로 저장됩니다 urls. 다음으로 배열을 반복하여 URL을 키로 저장합니다.연관 배열— 이는 고유성 문제를 해결합니다(그리고 발생 횟수는 각 항목의 값으로 유지됩니다).

Bash의 연관 배열에 익숙하지 않은 경우 두 번째 루프에는 추가 설명이 필요합니다. 이 표현은 "${unique[@]}"모든 것을 확장합니다.가치배열을 사용하여 "${!unique[@]}"모든 항목을 확장합니다.색인배열의 경우 다음을 사용하여 배열 데이터를 덤프하면 의미가 있습니다 declare -p unique.

declare -A unique=([https://google.com/411/201701_01_01.zip]="1" 
                   [https://google.com/411/201701_01_02.zip]="1" )

루프 내에서 이 모든 작업을 수행할 수도 있지만 알아내기가 약간 어려울 수 있습니다.

while read line; do
  [[ -n "$line" ]] && let unique[$line]++ 
done < <(xml sel -t -m  "/download-area/files/file" -v url  -nl <<< $XML)

xmlXMLstarlet은 다음 과 같이 설치할 수 있습니다 .xmlstarlet

답변4

sed를 사용하여 출력을 구문 분석하는 것을 고려하십시오 xmllint. 단축된 XPath 표현식을 참고하세요!

URL=$( echo $XML | xmllint --xpath "//url" - | sed -e 's/<url>//g' -e 's/<\/url>/\n/g' )

printf "%s\n" "$URL"

한 줄에 하나의 URL이 출력됩니다.

관련 정보