编码代理与终端 · 收录于 2026-08-29 · 适用 1 工具 ✓ 实测验证

docker exec 报 the input device is not a TTY / container is not running / executable file not found

已验证 2026-08-29docker exec 报 not a TTY——非交互执行去掉 -t,用 docker exec <容器> sh -c "命令"。

快速修复

# 一键:非交互执行,去掉 -t
docker exec <容器> sh -c "你的命令"

你会遇到什么

脚本、CI(Jenkins/GitHub Actions)或管道里跑 docker exec -it ... 报 the input device is not a TTY;同族还有 container is not running、exec: "bash": executable file not found in $PATH。手动在终端里跑同一命令却正常——所以总被当成玄学。

其实规律很简单:交互式命令(-t)在非终端环境里跑不了。

本文路径:快速修复(30 秒一段命令)→ 一步步排查(可跳读)→ 原理与变体(症状/原因/证据)。赶时间直接跳到「快速修复」。

为什么会这样

  • -t(--tty)要求分配 TTY 伪终端,脚本/CI 的标准输入不是终端,docker CLI 直接拒绝启动;
  • docker compose exec 默认带 -t,所以 compose 场景更容易踩;
  • container is not running:对已停止容器执行 exec;
  • executable file not found:alpine 等精简镜像没有 bash(只有 sh)。
实测环境:WSL Ubuntu,docker 29.1.3,alpine:3.20,2026-08-29。

-t 的语义是「让容器进程认为自己在终端里」:docker CLI 会为它分配一个伪终端(PTY)。PTY 只能建立在「客户端 stdin 是终端」的前提下;脚本/CI 里 stdin 是管道或文件,没有终端可分配,CLI 在启动前就拒绝。docker compose exec 默认带 -t,所以 compose 场景更容易踩。

确定性推论:报 the input device is not a TTY = 当前进程没有终端,去掉 -t(需要 stdin 时只留 -i);脚本里用 [ -t 0 ] 检测 stdin 是否终端来决定要不要 -t,不要拍脑袋写死。

一步步来

1. 非交互命令去掉 -t — 必做

docker exec <c> sh -c "命令"

需要 stdin 管道时只留 -i:

echo 数据 | docker exec -i <c> sh -c "cat"

(实测均可,exit 0。)

2. compose 场景 — 必做

docker compose exec -T <service> 命令

-T = 禁用 TTY。旧版 v1 可加 export COMPOSE_INTERACTIVE_NO_CLI=1,新版以 -T 为准。

3. 容器没在跑 — 必做

docker start <c>

先 docker logs <c> 看为什么退出(exit code 1 的容器先排查启动失败原因,别盲目 start)。

4. 镜像里没有目标命令 — 必做

docker exec <c> ls /bin /usr/bin

alpine 用 sh;要 bash 就换 ubuntu/debian 镜像,或 docker exec <c> sh -c "命令"。

真终端里交互式进入容器保持原样:docker exec -it <c> sh,不要去掉 -it。

怎么确认修好了

docker exec <c> sh -c "echo noninteractive-ok"

正常输出即成功。实测:echo hello | docker exec -i <c> sh -c "cat" → hello(exit 0);复现时 docker exec -it <c> sh </dev/null → the input device is not a TTY(exit 1)。

其它环境的表现

环境说明
脚本/CI/管道去掉 -t,只留 -i(需要 stdin 时)
docker composeexec -T 禁用 TTY
已停止容器container is not running,先 docker start / 查日志
alpine 精简镜像没有 bash,用 sh -c

症状

脚本、CI(Jenkins/GitHub Actions)或管道里跑 docker exec -it ... / docker compose exec ... 报:

the input device is not a TTY

同族症状:docker exec 进已停止容器报 Error response from daemon: container <id> is not running; 对 alpine 等精简镜像跑 docker exec <c> bash 报 exec: "bash": executable file not found in $PATH。 特征:交互式命令在没有终端的环境里执行;手动在终端里跑同一命令却正常——所以总被当成玄学。

原因

-t(--tty)要求分配一个 TTY 伪终端,脚本/CI 的标准输入不是终端,docker CLI 直接拒绝启动; docker compose exec 默认带 -t,所以 compose 场景更容易踩。

解法

  1. 非交互命令去掉 -t:docker exec <c> sh -c "命令";需要 stdin 管道时只留 -i:

echo 数据 | docker exec -i <c> sh -c "cat"(实测均可)。

  1. compose 场景:docker compose exec -T <service> 命令(-T = 禁用 TTY);

旧版 v1 可加 export COMPOSE_INTERACTIVE_NO_CLI=1,但新版本以 -T 为准。

  1. 判断 TTY:脚本里可用 [ -t 0 ] 检测 stdin 是否是终端,条件决定是否加 -t。
  2. 容器没在跑:先 docker start <c> 或 docker logs <c> 看为什么退出(exit code 1 的容器先排查启动失败原因,别盲目 start)。
  3. 没有目标命令:先 docker exec <c> ls /bin /usr/bin 看镜像里有什么;alpine 用 sh,要 bash 就换 ubuntu/debian 镜像,或 docker exec <c> sh -c "命令"。
  4. 交互式进入容器(真终端):docker exec -it <c> sh,保持 -it 不变。
验证证据
  • 本地实测(2026-08-29,WSL Ubuntu,docker 29.1.3,alpine:3.20):
  • 复现:docker exec -it <c> sh </dev/null(非 TTY)→ the input device is not a TTY(exit 1),与 compose#7306 同款;
  • 修复 1:echo hello | docker exec -i <c> sh -c "cat" → hello(exit 0);
  • 修复 2:docker exec <c> sh -c "echo noninteractive-ok" → 正常(exit 0);
  • 形态 2:容器 stop 后 docker exec <c> echo x → container ... is not running(exit 1);
  • 形态 3:docker exec <c> bash -c ... → exec: "bash": executable file not found in $PATH(exit 127);
  • 清理:容器删除无残留。
  • 实测复现日志(2026-08-29)

相关 canonical

按「前置 → 同根 / 同域 / 相关」读:

适用工具 (1)

本问题方案已挂到下列工具的方案页——从工具页也能回到这里,双向可达。

docker · 外部工具

来源与证据

收录 验证 ✓ 实测验证适用 1 工具
方案含本地实测或来源可复核的解法;未实测项已在文中如实标注。

素材来源:https://github.com/docker/compose/issues/7306

← 编码代理与终端 问题域 | 问题货架 | 遇到其它问题?去 问题空间 提交求助卡