Shell 使用 -ldflags 传递给 Go 编译器的字符串中的变量未展开

Shell variable in a string passed with -ldflags to the Go compiler is not expanded

我正在尝试让一个简单的构建 bash 脚本运行,但无法将日期作为参数。我在这里错过了什么?谢谢

#!/bin/bash
buildDate=$(date)
go build -ldflags='-X main.buildTimestamp=$buildDate' main.go

输出:Build: $buildDate

引用the documentation on a POSIX-compatible shell:

2.2.2 Single-Quotes

Enclosing characters in single-quotes ( '' ) shall preserve the literal value of each character within the single-quotes. A single-quote cannot occur within single-quotes.

因此,在您的特定情况下,bashgo build … 命令分解为单词并在实际执行命令之前执行字符串替换。

根据字符串替换规则,用单引号括起来的文本按字面意思,所以在扩展后 shell 查找 go 命令并执行它,将树结果参数传递给它,它们依次是:build-ldflags=-X main.buildTimestamp=$buildDatemain.go.

由于 Go 工具链在其工作过程中不会在任何地方调用 shell,因此文字文本 $buildDate 会未经修改地传递给编译器。

如果构建日期的格式不包含空格,最简单的解决方法是将单引号替换为双引号。

如果你需要在其中嵌入空格,它会变得有点棘手,但不会太多——引用 go build help:

的输出

The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a space-separated list of arguments to pass to an underlying tool during the build. To embed spaces in an element in the list, surround it with either single or double quotes. <…>

换句话说,命令行参数解析器考虑成对的 "s 和 's 来实现参数分组,在你的情况下你可以做

go build -ldflags="-X main.buildTimestamp='$buildDate'" main.go

以便 shell 去除外部双引号 替换 $buildDate 为其值——根据大小写的字符串替换规则双引号。
因此,如果您的构建日期格式包含空格,例如 Tue, 12 May 2020 20:53:16 +0300go 命令将接收以下三个参数,顺序为:build-ldflags=-X main.buildTimestamp='Tue, 12 May 2020 20:53:16 +0300'main.go,并且会自己处理那些单引号。