Разрешите имя файла от удаленного URL, не загружая файл

Используя bash и xmllint (как дано тегами):

xmllint --version  #  xmllint: using libxml version 20703

# Note: Newer versions of libxml / xmllint have a --xpath option which 
# makes it possible to use xpath expressions directly as arguments. 
# --xpath also enables precise output in contrast to the --shell & sed approaches below.
#xmllint --help 2>&1 | grep -i 'xpath'

{
# the given XML is in file.xml
host="$(echo "cat /config/global/resources/default_setup/connection/host/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
username="$(echo "cat /config/global/resources/default_setup/connection/username/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
password="$(echo "cat /config/global/resources/default_setup/connection/password/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
dbname="$(echo "cat /config/global/resources/default_setup/connection/dbname/text()" | xmllint --nocdata --shell file.xml | sed '1d;$d')"
printf '%s\n' "host: $host" "username: $username" "password: $password" "dbname: $dbname"
}

# output
# host: localhost
# username: root
# password: pass123
# dbname: testdb

В случае, если существует только строка XML, и использования временного файла нужно избежать, дескрипторы файлов являются способом пойти с xmllint (который дан /dev/fd/3 как аргумент файла здесь):

set +H
{
xmlstr='<?xml version="1.0"?>
<config>
    <global>
        <install>
            <date><![CDATA[Tue, 11 Dec 2012 12:31:25 +0000]]></date>
        </install>
        <crypt>
            <key><![CDATA[70e75d7969b900b696785f2f81ecb430]]></key>
        </crypt>
        <disable_local_modules>false</disable_local_modules>
        <resources>
            <db>
                <table_prefix><![CDATA[]]></table_prefix>
            </db>
            <default_setup>
                <connection>
                    <host><![CDATA[localhost]]></host>
                    <username><![CDATA[root]]></username>
                    <password><![CDATA[pass123]]></password>
                    <dbname><![CDATA[testdb]]></dbname>
                    <initStatements><![CDATA[SET NAMES utf8]]></initStatements>
                    <model><![CDATA[mysql4]]></model>
                    <type><![CDATA[pdo_mysql]]></type>
                    <pdoType><![CDATA[]]></pdoType>
                    <active>1</active>
                </connection>
            </default_setup>
        </resources>
        <session_save><![CDATA[files]]></session_save>
    </global>
    <admin>
        <routers>
            <adminhtml>
                <args>
                    <frontName><![CDATA[admin]]></frontName>
                </args>
            </adminhtml>
        </routers>
    </admin>
</config>
'

# exec issue
#exec 3<&- 3<<<"$xmlstr"
#exec 3<&- 3< <(printf '%s' "$xmlstr")
exec 3<&- 3<<EOF
$(printf '%s' "$xmlstr")
EOF

{ read -r host; read -r username; read -r password; read -r dbname; } < <(
       echo "cat /config/global/resources/default_setup/connection/*[self::host or self::username or self::password or self::dbname]/text()" | 
          xmllint --nocdata --shell /dev/fd/3 | 
          sed -e '1d;$d' -e '/^ *--* *$/d'
       )

printf '%s\n' "host: $host" "username: $username" "password: $password" "dbname: $dbname"

exec 3<&-
}
set -H


# output
# host: localhost
# username: root
# password: pass123
# dbname: testdb
5
24.04.2014, 10:21
2 ответа

Нечто подобное может сработать:

curl -sIkL http://repo1/xyz/LATEST | sed -r '/filename=/!d;s/.*filename=(.*)$/\1/'

Посмотрите на man-страницу curl(1) для опций. Интересным является -I, --head.

Пояснения по запросу согласно комментариям:

Идея заключается в том, чтобы запрашивать только заголовок ответа HTTP.

Поэтому используются опции -I. -s заглушает завихрение, чтобы не печатать ничего, кроме заголовка. -k допускает "небезопасные" SSL-соединения (Скручивание отвергло бы самоподписанные сертификаты в противном случае). А -L для отслеживания перенаправлений HTTP(S) местоположения.

Затем sed(1) используется для получения имени файла из заголовка ответа. Мы ищем поле filename=, поэтому часть /filename=/!d удаляет что-либо без этого поля из вывода. Наконец, часть s/.*filename=(.*)$/\1/ печатает имя файла только в том случае, если поле найдено.

.
6
27.01.2020, 20:35

Я пришел с этим решением, весьма похожим на решение @FloHimelves.

curl -L --head http://repo1/xyz/LATEST 2>/dev/null | grep Location: | tail -n1 | cut -d' ' -f2
  • -L позволяет curl следовать переадресации
  • --head заставляет его извлекать только заголовки, а не содержание страниц.
  • grep Location: ищет заголовок Location: в 30-кратных HTTP-ответах сервера
  • tail -n1 выбирает последнее
  • cut -d' ' -f2 выбирает второе поле (URL)

То же самое, но позволяя curl выполнять всю работу:

curl -L --head -w '%{url_effective}' http://repo1/xyz/LATEST  2>/dev/null | tail -n1

Это решение использует опцию -w, --write-out, чтобы запросить curl для конкретного вывода. man curl дает доступные переменные.

.
4
27.01.2020, 20:35

Теги

Похожие вопросы