将命令组直接放入 `docker exec`

Direct group of commands into `docker exec`

我有以下命令可以正常工作并在返回前打印 foo

docker exec -i <id> /bin/sh < echo "echo 'foo'"

我想用一根管道将多个命令定向到容器中,例如 echo 'foo'ls /。我尝试了以下方法:

  1. 这会失败,因为它 运行 在主机上发送命令并将输出通过管道传输到容器中:
    {
        echo "foo"
        ls /
    } | docker exec -i <id> /bin/sh
    
  2. 这失败了,因为它有错误的语法。它还在主机上 运行s:

    {
        echo "foo"
        ls /
    } | docker exec -i <id> /bin/sh
    
  3. 这个失败了,但无论如何我都不想使用字符串数组:

    for COMMAND in 'echo "foo"' 'ls /'
    do
        docker exec -i <id> /bin/sh < echo $COMMAND
    done
    

我还尝试了其他几种方法,例如将命令通过管道传输到 teeecho,但都没有成功。如果你想知道我为什么要做这件看似荒谬的事情,那是因为:

您可以运行以下方式的一组命令

 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 或其他解析工具来提取某些标记之间的唯一相关部分。