我正在编写一个 shell 脚本来下载某些软件的最新版本。在解析 的输出后,curl
我通过几个步骤来找到确切的版本字符串(在撰写本文时是0.65.3
):
(在下面的所有代码示例中,>
都是我的提示符。Bash 3.2 或 Zsh 的输出位于没有前缀的行上>
。)
> url="https://github.com/gohugoio/hugo/releases/latest"
> latest=$(curl --silent --head "$url" | grep Location)
> tag=$(echo "$latest" | cut -d'/' -f8)
> version=$(echo "${tag//v}")
> echo "hugo_${version}_Linux-64bit.tar.gz"
_Linux-64bit.tar.gz
我期望的输出是hugo_0.65.3_Linux-64bit.tar.gz
,但在使用带引号的字符串调用的输出中,echo
后面的字节似乎${version}
已用于覆盖带引号的字符串开头的字节。
这里我使用两个不同的带引号的字符串来阐明发生的情况:
> echo "hugo_${version}test"
test_0.65.3
> echo "hugo_${version}lorem ipsum dolor sit amet"
lorem ipsum dolor sit amet
我也得到同样的结果意外如果我这样做的话结果:
> version=$(echo "${tag:1}")
> echo "hugo_${version}_Linux-64bit.tar.gz"
_Linux-64bit.tar.gz
但是,我明白了预期的如果我这样做的话结果:
> version=0.65.3
hugo_0.65.3_Linux-64bit.tar.gz
最后一个结果是所需要的,但当然它使我的脚本静态而不是动态,因此对我来说不是很有用。如何在不对$version
脚本中的值进行硬编码的情况下获得所需的结果?
答案1
返回的行以curl
回车换行结束。 (MS-dos 行结尾)。 Unix 工具删除了换行符,但这会在末尾留下回车符。
修复此行以使用dos2unix
(并将您的参数引用到echo
,避免中描述的错误Bash 陷阱#14):
version="$(echo "${tag//v}" | dos2unix)"
...或者,使用 shell 的内置语法来执行两个都立即改变:
version=${tag//[$'v\r']/}
dos2unix
确实做了一些其他更改(例如在最后一行文本后添加尾随换行符,UNIX 需要但 DOS 不需要),但对于像这样的单行字符串来说,这些更改都不重要。
答案2
ctrl-alt-delor的回答解释您为何会看到此行为;但为了实现您的根本目标,我建议使用GitHub API而不是解释“最新”重定向:
version=$(curl https://api.github.com/repos/gohugoio/hugo/releases/latest | jq -r '.tag_name | ltrimstr("v")')
这会向 API 询问最新 Hugo 版本的信息,并使用以下命令提取标签名称jq
,去掉任何前导“v”。
理想情况下,您甚至可以从返回的 JSON 中提取资产名称和 URL。