这是我的第433篇原创文章。
一、引言
Dockerfile构建的Docker镜像,启动容器时找不到run.sh,执行docker run 命令时报错:/bin/sh: 1: /app/server/run.sh: not found
二、实现过程
2.1 缘由分析
造成这个问题的缘由主要有以下几点:
1、build image时没有把该脚本传入。start.sh文件的确 不在指定的目录下
2、权限问题:文件或文件夹权限设置不当,导致无法执行
3、文件内容与编码格式问题,如果Shell脚本在Windows系统下编辑,文件格式可能是DOS格式(CR+LF),而Linux系统只识别UNIX格式(LF)。
4、脚本文件的第一行指定了解释器,但解释器未安装。有些Shell脚本的第一行会指定一个解释器,如#!/bin/bash。如果容器内未安装该解释器,脚本将无法执行。请确保容器内安装了脚本所需的解释器。
2.2 编码格式排查
使用命令docker cp把start.sh从容器中拷贝出来(停止的容器也可以),然后使用命令cat -A run.sh,如果你命令后面跟的是$美元符号,那么祝贺你,文件是LF换行的,如果跟的是^M$符号,那么不好意思,是CRLF换行符。如果本地 run.sh 是 CRLF 换行,容器里会看成 #!/bin/bash
从而 “找不到解释器”。解决:本地一键转换(任选其一)
(1)Linux / macOS 已自带
dos2unix run.sh
# 没有就 sudo apt install dos2unix
(2)用 sed(无需安装)
sed-i's/
$//' run.sh
(3)Windows Git Bash / WSL
dos2unix run.sh
(4)VS Code
右下角点 “CRLF” → 选 “LF” → 保存。
验证是否改好
file run.sh
输出应出现run.sh: Bourne-Again shell script, ASCII text executable,不再有 “with CRLF line terminators”。
重新打镜像 / 推仓库
docker build -t myapp:new .
docker push myapp:new
让容器云重新拉最新镜像即可。kubectl 下可kubectl set image deployment/myapp myapp=myapp:new 触发滚动更新。
临时不想打镜像也能救:把脚本挂成 ConfigMap(LF),覆盖容器内文件:
kubectl create configmap run-sh --from-file=run.sh
kubectl patch deployment myapp --type merge -p '{"spec":{"template":{"spec":{"volumes":[{"name":"sh","configMap":{"name":"run-sh"}}],"containers":[{"name":"myapp","volumeMounts":[{"name":"sh","mountPath":"/app/build/run.sh","subPath":"run.sh"}]}]}}}}'
但根治还是源码里保持LF。
2.3 实际案例
假设你在Windows系统下编写了一个run.sh脚本,并将其复制到Docker容器中。在执行时遇到“找不到文件”的错误。
进入容器:
docker exec -it <container_id> /bin/bash
查文件路径:
pwd
ls -a
发现run.sh文件存在。
检查文件权限:
ls -l run.sh
发现没有执行权限。添加执行权限:
chmod +x run.sh
检查文件格式:
vi run.sh
:set ff
发现是DOS格式。转换为UNIX格式(方法见2.2):
:set ffunix
:wq
重新执行脚本:
./run.sh
脚本成功执行。
三、小结
在Docker容器内执行Shell脚本时,遇到“找不到文件”的错误,可能是由于文件路径、权限、格式、挂载或容器配置等问题引起的。通过逐步排查和解决这些问题,可以确保脚本在容器中顺利执行。希望本文提供的解决方法能协助你顺利解决这类问题,提高工作效率。
作者简介: 读研期间发表6篇SCI数据算法相关论文,目前在某研究院从事数据算法相关研究工作,结合自身科研实践经历持续分享关于Python、数据分析、特征工程、机器学习、深度学习、人工智能系列基础知识与案例。关注gzh:数据杂坛,获取数据和源码

















暂无评论内容