将命令组直接放入 `docker exec`
Direct group of commands into `docker exec`
我有以下命令可以正常工作并在返回前打印 foo
:
docker exec -i <id> /bin/sh < echo "echo 'foo'"
我想用一根管道将多个命令定向到容器中,例如 echo 'foo'
和 ls /
。我尝试了以下方法:
- 这会失败,因为它 运行 在主机上发送命令并将输出通过管道传输到容器中:
{
echo "foo"
ls /
} | docker exec -i <id> /bin/sh
这失败了,因为它有错误的语法。它还在主机上 运行s:
{
echo "foo"
ls /
} | docker exec -i <id> /bin/sh
这个失败了,但无论如何我都不想使用字符串数组:
for COMMAND in 'echo "foo"' 'ls /'
do
docker exec -i <id> /bin/sh < echo $COMMAND
done
我还尝试了其他几种方法,例如将命令通过管道传输到 tee
或 echo
,但都没有成功。如果你想知道我为什么要做这件看似荒谬的事情,那是因为:
- 这是一个简短的脚本,我想将其全部保存在一个地方
- 我想使用语法高亮,所以我不想将它全部存储在一个字符串列表中
- 容器有脚本应该运行的程序,而主机没有
- 这是一个自动进程,我想用主机上的 crontab 触发
您可以运行以下方式的一组命令
docker exec -i <id> /bin/sh -c 'echo "foo"; ls -l'
或
docker exec -i 996eee5d121d /bin/sh -c 'echo 'foo'; ls -l'
或
docker exec -i 996eee5d121d /bin/sh -c 'echo foo; ls -l'
如果你想 运行 超过 2 个命令,只需在每个命令后附加 ;
,如
docker exec -i 996eee5d121d /bin/sh -c 'echo "foo"; ls -l; ls -a'
我找到了一个 gist 来解释如何将命令通过管道传输到 docker exec
:
echo "echo foo" | docker exec -i <id> /bin/sh -
现在我们需要一种通过管道传输多个命令的方法。命令组将不起作用,因为它们在主机上 运行 并且以分号分隔的命令会变得混乱。我想写一个函数并只获取它的主体,事实证明你可以用一个简单的 declare
and sed
call.
您可以组合所有这些部分以将命令通过管道传输到容器中:
function func {
echo "foo"
ls /
}
declare -f func | sed '1,2d;$d' | docker exec -i <id> /bin/bash -
语法高亮在函数中仍然有效,并且易于阅读。
如果你想在容器中使用主机上的环境变量,你必须在 docker exec 中手动列出它们,如下所示:
... | docker exec -i -e VAR=$VAR <id> /bin/bash -
编辑:我把它留在这里作为一个可能的解决方案,但公认的答案是我正在使用的正确解决方案。
使用此处文档。
docker run -i --rm alpine /bin/sh <<EOF
echo abc
ls /
EOF
请注意此处引用和未引用的文档分隔符之间的区别。
docker exec -i <id> /bin/sh < echo "echo 'foo'"
我想你的意思是:
docker exec -i <id> /bin/sh < <(echo "echo 'foo'")
这与:
docker exec -i <id> /bin/sh <<<"echo 'foo'"
@edit 有一个很酷的小技巧。这个想法是将脚本本身通过管道传输到另一个子进程,除了第一行,它有时被安装程序脚本使用:
#!/bin/sh
# output this script except first 4 lines to docker
tail -n+5 "[=14=]" | docker run -i --rm alpine /bin/sh -x
exit # we exit original script
#!/bin/sh
# inside docker now
echo abc
ls /
执行:
$ bash -x ./script.sh
+ tail -n+5 ./script.sh
+ docker run -i --rm alpine /bin/sh -x
+ echo abc
+ ls /
abc
bin
...
var
+ exit
以类似的方式,您可以使用 sed
或其他解析工具来提取某些标记之间的唯一相关部分。
我有以下命令可以正常工作并在返回前打印 foo
:
docker exec -i <id> /bin/sh < echo "echo 'foo'"
我想用一根管道将多个命令定向到容器中,例如 echo 'foo'
和 ls /
。我尝试了以下方法:
- 这会失败,因为它 运行 在主机上发送命令并将输出通过管道传输到容器中:
{ echo "foo" ls / } | docker exec -i <id> /bin/sh
这失败了,因为它有错误的语法。它还在主机上 运行s:
{ echo "foo" ls / } | docker exec -i <id> /bin/sh
这个失败了,但无论如何我都不想使用字符串数组:
for COMMAND in 'echo "foo"' 'ls /' do docker exec -i <id> /bin/sh < echo $COMMAND done
我还尝试了其他几种方法,例如将命令通过管道传输到 tee
或 echo
,但都没有成功。如果你想知道我为什么要做这件看似荒谬的事情,那是因为:
- 这是一个简短的脚本,我想将其全部保存在一个地方
- 我想使用语法高亮,所以我不想将它全部存储在一个字符串列表中
- 容器有脚本应该运行的程序,而主机没有
- 这是一个自动进程,我想用主机上的 crontab 触发
您可以运行以下方式的一组命令
docker exec -i <id> /bin/sh -c 'echo "foo"; ls -l'
或
docker exec -i 996eee5d121d /bin/sh -c 'echo 'foo'; ls -l'
或
docker exec -i 996eee5d121d /bin/sh -c 'echo foo; ls -l'
如果你想 运行 超过 2 个命令,只需在每个命令后附加 ;
,如
docker exec -i 996eee5d121d /bin/sh -c 'echo "foo"; ls -l; ls -a'
我找到了一个 gist 来解释如何将命令通过管道传输到 docker exec
:
echo "echo foo" | docker exec -i <id> /bin/sh -
现在我们需要一种通过管道传输多个命令的方法。命令组将不起作用,因为它们在主机上 运行 并且以分号分隔的命令会变得混乱。我想写一个函数并只获取它的主体,事实证明你可以用一个简单的 declare
and sed
call.
您可以组合所有这些部分以将命令通过管道传输到容器中:
function func {
echo "foo"
ls /
}
declare -f func | sed '1,2d;$d' | docker exec -i <id> /bin/bash -
语法高亮在函数中仍然有效,并且易于阅读。
如果你想在容器中使用主机上的环境变量,你必须在 docker exec 中手动列出它们,如下所示:
... | docker exec -i -e VAR=$VAR <id> /bin/bash -
编辑:我把它留在这里作为一个可能的解决方案,但公认的答案是我正在使用的正确解决方案。
使用此处文档。
docker run -i --rm alpine /bin/sh <<EOF
echo abc
ls /
EOF
请注意此处引用和未引用的文档分隔符之间的区别。
docker exec -i <id> /bin/sh < echo "echo 'foo'"
我想你的意思是:
docker exec -i <id> /bin/sh < <(echo "echo 'foo'")
这与:
docker exec -i <id> /bin/sh <<<"echo 'foo'"
@edit 有一个很酷的小技巧。这个想法是将脚本本身通过管道传输到另一个子进程,除了第一行,它有时被安装程序脚本使用:
#!/bin/sh
# output this script except first 4 lines to docker
tail -n+5 "[=14=]" | docker run -i --rm alpine /bin/sh -x
exit # we exit original script
#!/bin/sh
# inside docker now
echo abc
ls /
执行:
$ bash -x ./script.sh
+ tail -n+5 ./script.sh
+ docker run -i --rm alpine /bin/sh -x
+ echo abc
+ ls /
abc
bin
...
var
+ exit
以类似的方式,您可以使用 sed
或其他解析工具来提取某些标记之间的唯一相关部分。