从远程 URL 解析文件名而不下载文件

从远程 URL 解析文件名而不下载文件

我正在创建一个脚本,该脚本应该从存储库下载最新版本的应用程序并部署该应用程序。

主要问题:有几个存储库,我需要检查其中哪个具有最新版本。

例如

http://repo1/xyz/LATEST -> (redirects to) -> http://repo1/xyz/app-1.0.0.0.zip
http://repo2/xyz/LATEST -> (redirects to) -> http://repo1/xyz/app-1.1.0.0.zip

因此,我需要迭代可用的存储库并仅获取文件名 - 无需下载过时版本的软件。

答案1

像这样的东西可能对你有用:

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

查看手册页curl(1)中的选项。有趣的是-I, --head

根据评论要求进行解释:

这个想法是仅请求 HTTP 响应标头。

因此-I使用这些选项。-s静音卷曲不打印标题以外的任何内容。-k允许“不安全”的 SSL 连接(否则,curl 会拒绝自签名证书)。并-L遵循 HTTP(S) 位置重定向。

然后sed(1)用于从响应头中获取文件名。我们正在搜索该filename=字段,因此该/filename=/!d部分会从输出中删除没有该字段的任何内容。最后,s/.*filename=(.*)$/\1/仅当找到该字段时,该部件才会打印文件名。

答案2

我想出了这个解决方案,与@FloHimself 的解决方案非常相似:

curl -L --head http://repo1/xyz/LATEST 2>/dev/null | grep Location: | tail -n1 | cut -d' ' -f2
  • -L让我们curl跟随重定向。
  • --head使其仅获取标题而不获取页面内容。
  • grep Location:Location:在服务器的 30x 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给出可用的变量。

答案3

@lgeorget 提供的答案非常接近,但仍然不理想。更好的解决方案是使用filename_effective变量--write-out。这仍然不完全理想,因为如果不下载文件它就无法工作。中也提到了man curl

filename_effective
   The ultimate filename that curl  writes  out  to.
   This  is only meaningful if curl is told to write
   to a file with the --remote-name or --output  op‐
   tion.  It's  most  useful in combination with the
   --remote-header-name option.

但是如果当前文件夹中已有该文件,那么它将抛出错误并丢弃下载的文件(在交互模式下,它会询问您是否要覆盖,但在非交互模式下,即在脚本中,它会抛出错误):

curl --remote-name \
     --remote-header-name \
     --location \
     --write-out '%{filename_effective}' \
     "${URL}"

因此,如果您想在脚本中使用它,您可以执行以下操作:

# just an example URL which will download Bitwarden's CLI software
URL='https://vault.bitwarden.com/download/?app=cli&platform=linux'

TMP_DOWNLOAD_RESULT="$(curl --remote-name \
                            --remote-header-name \
                            --location \
                            --write-out '%{exitcode};%{errormsg};%{filename_effective}' \
                            "${URL}")"

## break the result into its sub-parts
TMP_EXIT_CODE="$(echo "${TMP_DOWNLOAD_RESULT}" | cut -d ';' -f 1)"
TMP_EXIT_MESSAGE="$(echo "${TMP_DOWNLOAD_RESULT}" | cut -d ';' -f 2)"
TMP_REMOTE_FILE_NAME="$(echo "${TMP_DOWNLOAD_RESULT}" | cut -d ';' -f 3)"

# generate error or message of curl has failed.
if [ "${TMP_EXIT_CODE}" != "0" ]; then
    echo
    if [ "${TMP_EXIT_CODE}" == "23" ]; then
        echo "The local version is already the latest version."
        exit 0
    else
        echo "Downloading with cURL resulted in error number ${TMP_EXIT_CODE} with the message: \n\t${TMP_EXIT_MESSAGE}"
        exit 1
    fi
fi

相关内容