export GOPATH=~/mygo:~/go
export GOBIN=$GOPATH/bin
I expected the $GOBIN
equals ~/mygo/bin:~/go/bin
but it is ~/mygo:~/go/bin
instead.
how could I set them a better way? thx
export GOPATH=~/mygo:~/go
export GOBIN=${(j<:>)${${(s<:>)GOPATH}/%//bin}}
Although whatever program uses GOPATH
might interprete it as an array, for zsh
it is just a scalar ("string").
In order to append a string (/bin
) to every element the string "$GOPATH" first needs to be split into an array. In zsh
this can be done with the parameter expansion flag s:string:
. This splits a scalar on string
and returns an array. Instead of :
any other character or matching pairs of ()
, []
, {}
or <>
can be used. In this case it has to be done because string
is to be :
.
GOPATH_ARRAY=(${(s<:>)GOPATH)
Now the ${name/pattern/repl}
parameter expansion can be used to append /bin
to each element, or rather to replace the end of each element with /bin
. In order to match the end of a string, the pattern
needs to begin with a %
. As any string should be matched, the pattern is otherwise empty:
GOBIN_ARRAY=(${GOPATH_ARRAY/%//bin})
Finally, the array needs to be converted back into a colon-separated string. This can be done with the j:string:
parameter expansion flag. It is the counterpart to s:string:
:
GOBIN=${(j<:>)GOBIN_ARRAY}
Fortunately, zsh
allows Nested Substitution, so this can be done all in one statement, without intermediary variables:
GOBIN=${(j<:>)${${(s<:>)GOPATH}/%//bin}}
It is also possible to do this without parameter expansion flags or nested substitution by simply appending /bin
to the end of the string and additionally replace every :
with /bin:
:
export GOBIN=${GOPATH//://bin:}/bin
The ${name//pattern/repl}
expansion replaces every occurence of pattern
with repl
instead of just the first like with ${name/pattern/repl}
.
This would also work in bash
.
Personally, I feel that it is a bit "hackish", mainly because you need to write /bin
twice and also because it completely sidesteps the underlying semantics. But that is only personal preference and the results will be the same.
When defining GOPATH
like you did in the question
export GOPATH=~/mygo:~/go
zsh
will expand each occurence of ~/
with your home directory. So the value of GOPATH
will be /home/kevin/mygo:/home/kevin/go
- assuming the user name is "kevin". Accordingly, GOBIN
will also have the expanded paths, /home/kevin/mygo/bin:/home/kevin/go/bin
, instead of ~/mygo/bin:~/go/bin
This could be prevented by quoting the value - GOPATH="~/mygo:~/go"
- but I would recommend against it. ~
as synonym for the home directory is not a feature of the operating system and while shells usually support it, other programs (those needing GOPATH
or GOBIN
) might not do so.