我正在创建一个脚本,该脚本应该从存储库下载最新版本的应用程序并部署该应用程序。
主要问题:有几个存储库,我需要检查其中哪个具有最新版本。
例如
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