为何Docker不为CMD打开新的文件描述符fd?
问题分析与解决
问题根源
你遇到的报错是因为本地Shell提前解析了重定向参数,导致容器内的进程没有正确创建并继承文件描述符fd3。
当执行docker run --rm -v$PWD:$PWD -w$PWD ubuntu sh run.sh 3>&1 >/dev/null时,重定向逻辑是被你的本地Shell处理的:
- 本地Shell会先将容器进程的stdout(fd1)重定向到
/dev/null - 本地Shell创建的fd3并不会被Docker传递到容器内部——Docker默认仅保留stdin、stdout、stderr三个文件描述符,其他未明确指定的fd会被强制关闭。
因此容器内的run.sh尝试写入fd3时,就会触发"Bad file descriptor"错误。
解决方法
方法1:让容器内的Shell处理重定向
把包含重定向的命令用sh -c包裹,让容器内部的Shell来解析重定向参数,确保fd3在容器内正确创建:
docker run --rm -v$PWD:$PWD -w$PWD ubuntu sh -c "./run.sh 3>&1 >/dev/null"
此时容器内的Shell会先将fd3复制为当前的stdout(最终关联到你的终端),再将stdout重定向到/dev/null,run.sh里的echo Hello from me >&3就能正常输出到终端。
方法2:修改脚本兼容fd3不存在的情况
在run.sh开头添加检查逻辑,确保fd3始终处于可用状态(若未打开则绑定到stdout),这样不管是本地还是Docker环境都能兼容:
#!/bin/sh # 确保fd3已打开,若未打开则绑定到stdout [ -w /dev/fd/3 ] || exec 3>&1 echo No hello from me! echo Hello from me >&3
修改后,直接执行原Docker命令即可得到预期输出:
docker run --rm -v$PWD:$PWD -w$PWD ubuntu sh run.sh 3>&1 >/dev/null
内容的提问来源于stack exchange,提问作者Patrick Coppock
相关产品推荐
相关产品推荐

