Docker run执行mv命令报cannot stat错误,bash手动执行却正常
为什么Docker run直接执行mv带通配符报错,进入容器手动执行却正常?
这问题我熟得很!你碰到的是Docker命令执行时shell通配符展开时机的坑,我给你掰扯清楚:
核心原因:通配符被宿主机Shell解析了,而非容器内的Shell
1. 直接用docker run执行命令的场景
当你在宿主机终端输入这条命令时:
docker run -v D:/PKS/potree/test/dist:/data1 -v D:/PKS/potree/test/tiles:/data2 -v D:/PKS/potree/test/tmp:/data3 oscar/mpc:v1 mv /data1/execution4/*/* /data1/tmp2
你的宿主机Shell会先尝试解析命令里的通配符*——它会去宿主机的文件系统里找/data1/execution4/*/*这个路径,但/data1是容器内部的挂载路径,宿主机上根本不存在这个路径!所以通配符没有被展开,而是原封不动地作为参数传给了容器里的mv命令。
而mv命令本身是不认识通配符的,它只认具体的文件路径,自然会报错cannot stat '/data1/execution4/*/*': No such file or directory。
2. 进入容器bash后手动执行的场景
当你用docker exec或者docker run -it ... /bin/bash进入容器的bash环境后,所有命令都是在容器内部的Shell里执行的。此时容器里的/data1路径是存在的(因为挂载了宿主机目录),bash会自动把/data1/execution4/*/*展开成所有匹配的文件路径,mv拿到这些具体的路径,自然就能正常移动文件了。
解决办法:让容器内的Shell来解析通配符
要让命令正常工作,你需要显式调用容器内的Shell来处理通配符,把命令用bash -c(或sh -c,取决于镜像里的Shell)包裹起来:
docker run -v D:/PKS/potree/test/dist:/data1 -v D:/PKS/potree/test/tiles:/data2 -v D:/PKS/potree/test/tmp:/data3 oscar/mpc:v1 bash -c "mv /data1/execution4/*/* /data1/tmp2"
这样Docker会启动容器内的bash进程,由bash先解析通配符,再执行mv命令,就能和你手动进入容器执行的效果一致了。
内容的提问来源于stack exchange,提问作者Poul K. Sørensen
相关产品推荐
相关产品推荐

