我想区分导出到子进程的内联声明/定义的环境变量和已经存在/继承的环境变量。
$ export NODEJS=8
$ FU=BAR sh -c 'echo $FU $NODEJS'
具体用例是 cmd 包装器/装饰器,我们在其中封装容器使用情况(这只是一个示例)。
/tmp $ cat ./go.sh
#!/bin/sh
set -eu
docker run \
--rm \
--volume $PWD:/opt/main \
--workdir /opt/main \
golang:1.15 go "${@--h}"
/tmp $ go version
go version go1.15.5 darwin/amd64
/tmp $ mkdir -p /tmp/bin
/tmp $ ln -sf /tmp/go.sh /tmp/bin/go
/tmp $ chmod +x /tmp/go.sh
/tmp $ PATH=/tmp/bin:$PATH
/tmp $ go version
Unable to find image 'golang:1.15' locally
1.15: Pulling from library/golang
756975cb9c7e: Pull complete
d77915b4e630: Pull complete
5f37a0a41b6b: Pull complete
96b2c1e36db5: Pull complete
145393847161: Pull complete
3f8843661db9: Pull complete
218d240e42d4: Pull complete
Digest: sha256:0edb8df3d92a2ccf84d3245c8b0cc31edd6d23f9c3da3e07c8e2bd96eea34547
Status: Downloaded newer image for golang:1.15
go version go1.15.6 linux/amd64
我强调封装,因为对于上述包装器脚本的最终用户来说,无论我们从 Darwin 主机还是容器调用,在接口和/或期望方面都不应该有任何差异。这意味着,没有像下面这样的空白环境:
/tmp $ env -i FU=BAR sh -c 'echo $FU $NODEJS'
BAR
要将环境变量传递给 docker 运行时,我可以这样做:
$ cat <<eof | head -n3
> docker run \
> --rm \
> --volume $PWD:/opt/main \
> --workdir /opt/main \
> $( env -0 | xargs -0 -L1 printf '--env "%s"\n' ) \
> golang:1.15 go "${@--h}"
> eof
docker run --rm --volume /tmp:/opt/main --workdir /opt/main --env "TERM_PROGRAM=Apple_Terminal"
--env "SHELL=/bin/bash"
--env "TERM=xterm-256color"
...
当覆盖 shell 操作环境(如,嗯,,等)时,这会严重破坏。SHELL
我们PATH
可以使用额外的清单 y 环境(如 ENVS)将要使用的环境列入白名单,但由于几个原因,这是有问题的。
$ cat /tmp/go.sh
#!/bin/sh
set -eu
cat <<eof
docker run \
--rm \
--volume $PWD:/opt/main \
--workdir /opt/main \
$( echo $ENVS | xargs -n1 -- sh -c 'printf -- "--env %s=%s\n" $1 ${!1}' _) \
golang:1.15 go "${@--h}"
eof
$ ENVS="FU NODEJS" FU=BAR /tmp/go.sh
docker run --rm --volume /tmp:/opt/main --workdir /opt/main --env FU=BAR
--env NODEJS=8 golang:1.15 go "-h"
首先,它确实很混乱,其次,它违反了包装器的预期行为应与底层目标的预期行为相匹配的原则。如果我将 envs 传递给我的 go 命令,如下所示,并且它们不起作用,并且我花了一天时间才意识到它们需要在 中指定ENVS
,我会不太兴奋。
# fails to build appropriately targeted binary, but doesn't fail to build
$ GOOS=linux GOARCH=ppc64 go build
# this makes me mad
$ ENVS="GOOS GOARCH" GOOS=linux GOARCH=ppc64 go build
我不知道除了明显的硬编码之外是否有任何不同的方法来解决这个问题,但如果有人有任何过于聪明和简洁的东西,我很乐意看到它。