为什么双引号字符串中变量扩展后的字节会覆盖前面的字节?

为什么双引号字符串中变量扩展后的字节会覆盖前面的字节?

我正在编写一个 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。

相关内容