Bash 从另一个命令获取某些环境变量后,在远程主机上运行的docker容器中运行任意命令
为了说明我正在尝试做什么,这是我到目前为止使用的bash脚本的一部分:Bash 从另一个命令获取某些环境变量后,在远程主机上运行的docker容器中运行任意命令,bash,shell,docker,ssh,Bash,Shell,Docker,Ssh,为了说明我正在尝试做什么,这是我到目前为止使用的bash脚本的一部分: COMMAND="${@:1}" CONTAINER_DOCKER_NAME=this-value-is-computed-prior MY_IP=this-ip-is-computed-prior ssh user@$MY_IP -t 'bash -c "docker exec -it $( docker ps -a -q -f name='$CONTAINER_DOCKER_NAME' | head -n 1 ) /b
COMMAND="${@:1}"
CONTAINER_DOCKER_NAME=this-value-is-computed-prior
MY_IP=this-ip-is-computed-prior
ssh user@$MY_IP -t 'bash -c "docker exec -it $( docker ps -a -q -f name='$CONTAINER_DOCKER_NAME' | head -n 1 ) /bin/sh -c "eval $(echo export FOO=$BAR) && $COMMAND""'
因此,让我们分解长命令:我正在进入一个主机,在那里我运行一个bash,它用
docker ps
获取正确的容器,然后我执行docker exec
在容器中运行一个shell来加载我的$COMMAND
需要工作的一些环境变量。需要注意的重要一点是,$BAR
应该是容器内BAR
变量的值所以这就是我在理论上想要实现的。但是,在运行此命令时,无论我如何设置大括号、引号或转义字符,我总是会遇到问题,要么shell语法不正确,要么它没有运行正确的命令(尤其是当命令有多个参数时)或者它从本地桌面或远程主机加载
$BAR
值,但不从容器加载
用一个单壳单衬套就可以做到这一点吗?我认为我们可以大大简化您的命令 首先,这里不需要使用
eval
,也不需要&
接线员:
/bin/sh -c "eval $(echo export FOO=$BAR) && $COMMAND"
相反:
/bin/sh -c "FOO=$BAR $COMMAND"
设置环境变量FOO
的持续时间
$COMMAND
接下来,您不需要这个复杂的docker ps
表达式:
docker ps -a -q -f name="$CONTAINER_DOCKER_NAME"
Docker容器名称是唯一的。如果你有一个容器名
存储在$CONTAINER\u DOCKER\u NAME
中,您只需运行:
docker exec -it $CONTAINER_DOCKER_NAME ...
这将docker
命令简化为:
docker exec -it $CONTAINER_DOCKER_NAME \
/bin/sh -c "FOO=\$BAR $COMMAND"
注意我们是如何在$BAR
中转义$
的,因为我们需要它
在容器内部解释,而不是由当前shell解释。
现在,我们只需要安排通过ssh
运行这个。有一对
解决办法。我们可以确保保护地球上的一切
命令行针对额外级别的shell扩展,如
这:
我们需要将整个命令用双引号括起来,这意味着
需要在命令中转义任何引号(我们不能使用单引号)
引号,因为我们实际上想要展开变量
$CONTAINER\u DOCKER\u NAME
本地)。我们将失去一个级别的
\
扩展,因此我们的\$BAR
成为\\$BAR
如果您的命令不是交互式的,您可以将其减少一点
通过将脚本管道化到bash而不是将其包含在
命令行,如下所示:
ssh user@$MY_IP docker exec -i $CONTAINER_DOCKER_NAME /bin/sh <<EOF
FOO=\$BAR $COMMAND
EOF
ssh user@$MY\u IP docker exec-i$CONTAINER\u docker\u NAME/bin/sh我认为我们可以简化您的命令
首先,这里不需要使用eval
,也不需要&
接线员:
/bin/sh -c "eval $(echo export FOO=$BAR) && $COMMAND"
相反:
/bin/sh -c "FOO=$BAR $COMMAND"
设置环境变量FOO
的持续时间
$COMMAND
接下来,您不需要这个复杂的docker ps
表达式:
docker ps -a -q -f name="$CONTAINER_DOCKER_NAME"
Docker容器名称是唯一的。如果你有一个容器名
存储在$CONTAINER\u DOCKER\u NAME
中,您只需运行:
docker exec -it $CONTAINER_DOCKER_NAME ...
这将docker
命令简化为:
docker exec -it $CONTAINER_DOCKER_NAME \
/bin/sh -c "FOO=\$BAR $COMMAND"
注意我们是如何在$BAR
中转义$
的,因为我们需要它
在容器内部解释,而不是由当前shell解释。
现在,我们只需要安排通过ssh
运行这个。有一对
解决办法。我们可以确保保护地球上的一切
命令行针对额外级别的shell扩展,如
这:
我们需要将整个命令用双引号括起来,这意味着
需要在命令中转义任何引号(我们不能使用单引号)
引号,因为我们实际上想要展开变量
$CONTAINER\u DOCKER\u NAME
本地)。我们将失去一个级别的
\
扩展,因此我们的\$BAR
成为\\$BAR
如果您的命令不是交互式的,您可以将其减少一点
通过将脚本管道化到bash而不是将其包含在
命令行,如下所示:
ssh user@$MY_IP docker exec -i $CONTAINER_DOCKER_NAME /bin/sh <<EOF
FOO=\$BAR $COMMAND
EOF
ssh user@$MY_IP docker exec-i$CONTAINER_docker_NAME/bin/sh多亏了larsks的精彩解释,我的最后一行代码是:
ssh -i $ECS_SSH_KEY ec2-user@$EC2_IP -t "bash -c \"docker exec -it \$( docker ps -a -q -f name=$CONTAINER_DOCKER_NAME | head -n 1 ) /bin/sh -c \\\"eval \\\\\\\$(AWS_ENV_PATH=/\\\\\\\$ENVIRONMENT /bin/aws-env) && $COMMAND\\\"\""
所以基本上你把所有东西都用双引号括起来,然后在里面用双引号,因为我们需要一些变量,比如主机的$DOCKER\u CONTAINER\u NAME
。转义引号和您使用的$符号\。
但是因为我们有多个级别的shell(主机、服务器、容器),所以我们还需要使用多个级别的转义。因此,第一级是\$,它将保护变量(或shell命令,如docker ps
)不是在主机上运行,而是在服务器上运行。
那么下一级逃逸是7次\。every\向右转义字符,因此最后它在第二级(服务器)上是\\\$
,在第三级(容器)上是\$
。这样可以确保在容器中而不是在服务器上计算变量。
双引号的原理是一样的。\“
之间的所有内容都在第二级运行,而\\”
之间的所有内容都在第三级运行。多亏拉尔克斯的精彩解释,我的最后一句话是:
ssh -i $ECS_SSH_KEY ec2-user@$EC2_IP -t "bash -c \"docker exec -it \$( docker ps -a -q -f name=$CONTAINER_DOCKER_NAME | head -n 1 ) /bin/sh -c \\\"eval \\\\\\\$(AWS_ENV_PATH=/\\\\\\\$ENVIRONMENT /bin/aws-env) && $COMMAND\\\"\""
所以基本上你把所有东西都用双引号括起来,然后在里面用双引号,因为我们需要一些变量,比如主机的$DOCKER\u CONTAINER\u NAME
。转义引号和您使用的$符号\。
但是因为我们有多个级别的shell(主机、服务器、容器),所以我们还需要使用多个级别的转义。因此,第一级是\$,它将保护变量(或shell命令,如docker ps
)不是在主机上运行,而是在服务器上运行。
那么下一级逃逸是7次\。每个\转义字符