Bash – Escape parameters for positional arguments

bashgentoo

I have external bash script which is called by system with bash to compile golang sources, and I'm able to configure some varialbes. This script is a golang-build.eclass. The build function in this script is:

golang-build_src_compile() {
    debug-print-function ${FUNCNAME} "$@"

    ego_pn_check
    set -- env GOPATH="${WORKDIR}/${P}:$(get_golibdir_gopath)" \
        GOCACHE="${T}/go-cache" \
        go build -v -work -x ${EGO_BUILD_FLAGS} "${EGO_PN}"
    echo "$@"
    "$@" || die
}

The only thing I can configure from outside is EGO_BUILD_FLAGS variable.

The problem with this script is when I'm trying to use quotes in EGO_BUILD_FLAGS variable, e.g.:

EGO_BUILD_FLAGS="-ldflags \"-X main.buildVersion=0\""

build script is printing (with echo) correct command to execute but actual command fails with error invalid value "\"-X" for flag -ldflags. If I just copy printed output and run it manually it completed successfully.

Here is simplified version to reproduce it:

EGO_BUILD_FLAGS="-ldflags \"-X main.buildVersion=0\""
set -- go build -x ${EGO_BUILD_FLAGS} github.com/g4s8/gitstrap/cmd/gitstrap
echo "$@"
"$@"

the output:

go build -x -ldflags "-X main.buildVersion=0" github.com/g4s8/gitstrap/cmd/gitstrap
invalid value "\"-X" for flag -ldflags: missing =<value> in <pattern>=<value>
usage: go build [-o output] [-i] [build flags] [packages]
Run 'go help build' for details.

The first line here is working command and looks like expected.
It seems that the problem here is that $4 is "-X and $5 is main.buildVersion=0".

Is it possible to escape quotes to pass correct build parameters as positional arguments to set from script variable?

The only possible solution here is to change EGO_BUILD_FLAGS variable, set -- ... command is not accessible, it's located in external script file.

Best Answer

The quoting is simple, you can just use single quotes instead of double ones:

EGO_BUILD_FLAGS='-ldflags "-X main.buildVersion=0"'

But that isn't the source of the problem:

$ go build -x ${EGO_BUILD_FLAGS} github.com/g4s8/gitstrap/cmd/gitstrap
invalid value "\"-X" for flag -ldflags: missing =<value> in <pattern>=<value>
usage: go build [-o output] [-i] [build flags] [packages]
Run 'go help build' for details.

The problem is that you are passing the variable's contents as a single value. See what happens if you run this with set -x:

$ set -x
$ go build -x ${EGO_BUILD_FLAGS} github.com/g4s8/gitstrap/cmd/gitstrap
+ go build -x -ldflags '"-X' 'main.buildVersion=0"' github.com/g4s8/gitstrap/cmd/gitstrap
invalid value "\"-X" for flag -ldflags: missing =<value> in <pattern>=<value>
usage: go build [-o output] [-i] [build flags] [packages]
Run 'go help build' for details.

The simplest solution is to remove the -ldflags from your variable and only store the values you want to pass with -ldflags. You can then use your variable as you want:

EGO_BUILD_FLAGS='-X main.buildVersion=0'
go build -x -ldflags ${EGO_BUILD_FLAGS} github.com/g4s8/gitstrap/cmd/gitstrap

If that is not an option, you can use an array instead:

EGO_BUILD_FLAGS=('-ldflags' '-X' 'main.buildVersion=0')
go build -x "${EGO_BUILD_FLAGS[@]}" github.com/g4s8/gitstrap/cmd/gitstrap

Finally, you could just not quote the values you set in the variable:

EGO_BUILD_FLAGS='-ldflags -X main.buildVersion=0'
Related Question