서비스에서 일부 파일을 다운로드하려고 합니다. 이러한 파일은 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
xmllint
XML 문서에서 정보를 추출하는 것은 쓸모가 없습니다. xmlstarlet
or 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
xmllint
XML을 분할하는 데는 좋은 도구가 아닙니다. 두 가지 문제(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
-v
url
-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)
xml
XMLstarlet은 다음 과 같이 설치할 수 있습니다 .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이 출력됩니다.