元数据
| id | docker-exec-tty | 收录 | 2026-08-29 |
|---|---|---|---|
| 问题域 | 编码代理与终端 | 主题分组 | 容器与 WSL |
| 适用工具 | docker · 外部工具 | ||
症状
脚本、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"`(实测均可)。
2. **compose 场景**:`docker compose exec -T <service> 命令`(-T = 禁用 TTY);
旧版 v1 可加 `export COMPOSE_INTERACTIVE_NO_CLI=1`,但新版本以 `-T` 为准。
3. **判断 TTY**:脚本里可用 `[ -t 0 ]` 检测 stdin 是否是终端,条件决定是否加 `-t`。
4. **容器没在跑**:先 `docker start <c>` 或 `docker logs <c>` 看为什么退出(exit code 1 的容器先排查启动失败原因,别盲目 start)。
5. **没有目标命令**:先 `docker exec <c> ls /bin /usr/bin` 看镜像里有什么;alpine 用 `sh`,要 bash 就换 ubuntu/debian 镜像,或 `docker exec <c> sh -c "命令"`。
6. 交互式进入容器(真终端):`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)
来源与证据
素材来源:https://github.com/docker/compose/issues/7306
验证证据:Evidence details kept locally (2026-08-29)