我正在尝试使用参数扩展$@
取消引用环境变量的值,但它似乎不起作用。
我需要调用带有某些参数的 shell 脚本。参数列表包含环境变量,并且环境变量应存在于要执行 shell 脚本的位置。我事先不知道命令列表,所以我使用$@
扩展这些命令列表。但是,该脚本无法取消引用环境变量的值。
可以按如下方式进行解释我的问题的最小设置。
- Dockerfile
FROM alpine:3.10
ENV MY_VAR=production
WORKDIR /app
COPY run.sh .
ENTRYPOINT [ "sh", "run.sh" ]
- run.sh
#!/bin/sh
echo "Value of MY_VAR is" $MY_VAR
echo "Begin"
$@
echo "Done"
我可以使用docker build . -t env-test
构建映像。当我使用docker run env-test:latest 'echo $MY_VAR'
运行它时,我得到以下输出。
Value of MY_VAR is production
Begin
$MY_VAR
Done
而我期望的输出是:
Value of MY_VAR is production
Begin
production
Done
旁注:实际上,我正在尝试使用如下所示的撰写文件运行它:
version: '3'
services:
run:
image: env-test:latest
command: echo $$MY_VAR
但它再次给了我类似的结果。
扩展eval
方法,下面是一个简单的 bash 脚本,它将使用 eval 将字符串作为一系列 bash 命令进行评估:
#!/usr/bin/env bash
echo program args: $@
eval $@
但要注意,eval
伴随着危险:
https://medium.com/dot-debug/the-perils-of-bash-eval-cc5f9e309cae
第一件事,$@
它只会打印参数的数量
#!/bin/sh
echo "Value of MY_VAR is" $MY_VAR
echo "Begin"
$@
echo "Done"
$@ = 将所有参数存储在字符串列表中
$* = 将所有参数存储为单个字符串
$# = 存储参数的数量
$@ 在 shell 脚本中是什么意思?
第二件事,当运行以下命令时
docker run env-test:latest 'echo $MY_VAR'
它将在主机系统中查找 $MY_VAR,而不是在容器中查找。
要访问容器环境,您必须将它们作为-e MY_VAR=test
传递,而不是作为 docker run 命令的参数传递,该命令将在主机中的 ENV 中传递。
docker run -e MY_VAR=test env-test:latest
所以MY_VAR
的价值将是test
而不是production
.
调试参数以docker run
export MY_VAR2="value_from_host"
现在运行
docker run env-test:latest "echo $MY_VAR2"
因此,该值将value_from_host
,因为该参数从主机中选取。
还有更多方法可以给这只特殊的猫剥皮:
me@computer:~$ docker run -it --rm ubuntu:20.04 bash -c 'echo $HOSTNAME'
e610946f50c1
在这里,我们呼吁容器内的bash 来处理单引号内的所有内容,因此变量替换和/或扩展不是由你的 shell 应用,而是由容器内的 shell 应用。
另一种方法是:
me@computer:~$ cat test.sh
#!/bin/bash
echo $HOSTNAME
me@computer:~$ cat test.sh | docker run -i --rm ubuntu:20.04 bash
62ba950a60fe
在这种情况下,cat
将脚本的内容"推送"到bash
容器中,因此它在功能上等效于我的第一个示例。第一种方法是"更干净的",但是如果你有一个更复杂的脚本,多行变量或其他难以放入单个命令中的东西,那么第二种方法是更好的选择。
注意:每个示例中的主机名都不同,因为我使用的是--rm
选项,该选项在容器退出后会丢弃容器。当您想在容器中运行命令但之后不需要保留容器时,这非常有用。