1. 简介

我们通常使用 docker exec 在一个已经运行的容器中执行命令。然而,docker exec 本身并不支持直接执行多个命令的链式调用。因此,当我们需要执行多个命令时,就需要借助 shell 进程或使用其他技巧来实现。

在本文中,我们将探讨几种常见的方法来实现通过 docker exec 执行多个命令。


2. 在 Shell 进程中使用命令链操作符

我们可以通过 docker exec 启动一个 shell 进程,然后在这个进程中执行多个命令。常用的方式是使用 bash -c 来执行多条命令:

$ docker exec [container_name] bash -c "[command1] && [command2] && [command3]"

上面的 && 表示逻辑“与”,意味着只有当前面的命令执行成功时,后面的命令才会继续执行。

如果我们希望无论前面命令是否成功,后面的命令都执行,可以使用分号 ;

$ docker exec [container_name] bash -c "[command1]; [command2]; [command3]"

如果我们希望只有前面的命令执行失败时才执行后面的命令,可以使用 ||

$ docker exec [container_name] bash -c "[command1] || [command2] || [command3]"

对于比较长的命令,我们也可以使用反斜杠 \ 拆分成多行书写,提高可读性:

$ docker exec [container_name] bash -c "[command1] \
&& [command2] \
&& [command3]"

优点:语法清晰,适合一次性执行多个命令。
缺点:如果命令之间有依赖关系,需要注意执行顺序和失败处理。


3. 将脚本文件重定向到 Shell 输入

如果我们已经写好了一个脚本文件,里面包含多个命令,可以直接将该文件内容通过输入重定向的方式传递给 docker exec 创建的 shell 进程:

$ docker exec -i [container_name] sh < [script_file]

⚠️ 注意:必须加上 -i 参数,否则 shell 进程的标准输入不会连接到容器,也无法读取脚本内容。

优点:适合复杂脚本的执行,结构清晰。
缺点:需要维护脚本文件,不适合临时快速执行。


4. 使用 Here Document 传递多行命令

和上面类似,我们也可以使用 Here Document(简称 heredoc)方式将多行命令传递给 shell 进程:

$ docker exec -i [container_name] bash << EOF
[command1]
[command2]
[command3]
EOF

也可以通过管道方式传递:

$ cat << EOF | docker exec -i [container_name] bash
[command1]
[command2]
[command3]
EOF

⚠️ 注意:直接使用 heredoc 更加高效,因为不需要额外的 cat 进程。

优点:无需创建临时文件,适合一次性多命令执行。
缺点:不适合大量命令或复杂逻辑。


5. 启动交互式 Shell 会话

如果我们需要在一个会话中连续执行多个命令,可以启动一个交互式的 shell 会话:

$ docker exec -it [container_name] bash

其中:

  • -t 表示分配一个伪终端(pseudo-TTY)
  • -i 表示保持标准输入打开(interactive)

⚠️ 注意:缺少 -i 将无法交互输入,缺少 -t 将无法获得终端界面。

优点:可以像在本地 shell 一样操作,适合调试或临时执行多个命令。
缺点:退出后无法继续执行,不适合自动化。


6. 使用 for 或 while 循环执行多个命令

我们也可以通过 shell 脚本结合 forwhile 循环,依次执行多个 docker exec 命令。

例如,使用 while 循环从标准输入读取命令:

$ cat docker_exec.sh
#!/bin/bash
while read command
do
    docker exec [container_name] $command
done

也可以从文件中读取命令:

$ cat docker_exec.sh
#!/bin/bash
while read command
do
    docker exec [container_name] $command
done < commands.txt

使用 for 循环显式执行命令:

$ cat docker_exec.sh
#!/bin/bash
for command in "command1" "command2"
do
    docker exec [container_name] $command
done

⚠️ 注意:如果命令之间有依赖关系,必须确保前面的 docker exec 命令产生的变更对后续命令有效(例如文件写入、环境变量设置等)。

优点:适合自动化脚本,灵活控制执行逻辑。
缺点:依赖关系处理复杂。


7. 利用 docker exec 自带选项替代部分命令

某些常见的命令组合可以被 docker exec 的选项替代,从而避免使用 shell 链式命令。

指定工作目录(代替 cd

$ docker exec -w [target_directory] [container_name] [command_to_execute]

-w--workdir 可以指定命令执行的工作目录,等价于 cd [dir] && [command]

设置环境变量(代替 export

$ docker exec -e [variable=value] [container_name] env

-e--env 用于设置环境变量,等价于 export VAR=VAL && env

指定执行用户(代替 su

$ docker exec -u [username] [container_name] whoami

-u--user 用于切换执行用户,避免使用 susudo

优点:命令更简洁,减少依赖 shell。
缺点:功能有限,不能替代所有 shell 命令组合。


8. 总结

方法 适用场景 是否支持命令依赖 是否适合自动化
命令链操作符 简单多命令执行
脚本文件重定向 复杂逻辑执行
Heredoc 临时多命令
交互式 shell 调试/手动执行
Shell 循环 自动化脚本
Docker exec 选项 替代简单命令

在实际开发或运维中,可以根据具体需求选择合适的方法。例如,调试时使用交互式 shell 最方便,自动化脚本中则推荐使用命令链操作符或循环调用方式。


📌 小贴士

  • 使用 -i 是很多命令能正常执行的前提,别忘了加上
  • 多命令之间如果有依赖,建议使用 shell 进程方式或交互式会话
  • 如果命令逻辑复杂,建议写成脚本文件并使用重定向方式执行,便于维护和复用

原始标题:Executing Multiple Commands with docker exec