サービスからいくつかのファイルをダウンロードしようとしています。これらのファイルはXMLファイルにあります。 XMLファイルには、ダウンロードするファイルが1つ以上ある場合があります。しかし、今スクリプトに問題があります。各ファイルを個別にダウンロードできるように、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
一度に1つの文字列を抽出できます。
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を分割するのに良いツールではありません。 2つの問題(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
また、リダイレクトを使用して/パイプを<<<
保存しますecho
。
URLは通常のインデックス配列として保存されますurls
。次に、配列を繰り返してURLをキーとして保存します。連想配列- これは一意性の問題を解決します(そして発生回数は各項目の値のままです)。
Bashの連想配列に慣れていない場合、2番目のループには追加の説明が必要です。この表現は"${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"
1行に1つのURLが出力されます。