在 shell 脚本中取消引用参数扩展时的环境变量



我正在尝试使用参数扩展$@取消引用环境变量的值,但它似乎不起作用。

我需要调用带有某些参数的 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选项,该选项在容器退出后会丢弃容器。当您想在容器中运行命令但之后不需要保留容器时,这非常有用。

最新更新