运行 使用 Docker Alpine 对本地文件执行 shell 命令
Running a shell command on local files with Docker Alpine
我的目录中充满了扩展名为 .dic
的文件,我需要(递归地)重命名它们以获得扩展名为 .dcm
。但是,我需要通过 运行 将 Docker 的卷安装在本地文件上来完成此操作。
因此,我拉取了 Alpine Docker 图像并开始使用它。由于 Alpine 镜像中没有 rename
命令,我使用 find
、mv
和 sed
:
1) 运行 来自 Alpine 镜像的容器,在 /tmp
中挂载我的本地目录,并在容器中启动一个 shell 会话:
docker run -ti -v `pwd`:/tmp alpine /bin/sh
2) 在容器内,运行重命名命令:
find /tmp -name '*.dic' | while read filename; do mv ${filename} $(echo ${filename} | sed -e 's/\.dic$/\.dcm/'); done
这工作正常,但我真正需要做的是启动容器,运行 命令,然后退出。所以我尝试了:
docker run -v `pwd`:/tmp alpine /bin/sh -c "find /tmp -name '*.dic' | while read filename; do mv ${filename} $(echo ${filename} | sed -e 's/\.dic$/\.dcm/'); done"
但它不起作用,文件未重命名,输出为:
BusyBox v1.28.4 (2018-05-30 10:45:57 UTC) multi-call binary.
Usage: mv [-fin] SOURCE DEST
or: mv [-fin] SOURCE... DIRECTORY
Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY
-f Don't prompt before overwriting
-i Interactive, prompt before overwrite
-n Don't overwrite an existing file
... 对找到的每个要重命名的文件重复一次。
我做错了什么?
遗憾的是 aplpine 没有重命名,加上复杂* bash 命令超过 docker cli 是一个奇怪的动物
我试了几次……但精神很好:)
试试这个:
docker run -v `pwd`:/tmp alpine /bin/sh -c "find /tmp -name '*.dic' -exec sh -c 'mv $"0" $"{0%.dic}".dcm' {} \;"
它不起作用的原因是因为使用双引号来包裹字符串意味着变量(例如${filename}
)被插值到 Alpine 外部 shell。您真正想要的是将字符串传递到单引号内的容器中,以便在容器内进行插值。
以下工作通过使用单引号字符串进行嵌套重命名,其中包含双引号字符串(与问题相反):
docker run -v pwd:/tmp alpine /bin/sh -c 'find /tmp -name "*.dic" | while read filename; do mv ${filename} $(echo ${filename} | sed -e "s/\.dic$/\.dcm/"); done'
然而,尽管这可行,但它并不是完美的解决方案。在执行的命令中保留使用单引号的另一种方法是将单引号包裹在双引号中并将其粘合到字符串中,例如“'”'s/find/replace/g'“'”。无数额外的引号和较低的易读性是否值得是 reader 的问题。那看起来像这样:
docker run -v pwd:/tmp alpine /bin/sh -c 'find /tmp -name '"'"'*.dic'"'"' | while read filename; do mv ${filename} $(echo ${filename} | sed -e '"'"'s/\.dic$/\.dcm/'"'"'); done'
TBH 我通常通过将命令放入脚本文件并将其包含在安装中来解决这种争论,因为脚本可以更容易地 shared/version 控制。
我的目录中充满了扩展名为 .dic
的文件,我需要(递归地)重命名它们以获得扩展名为 .dcm
。但是,我需要通过 运行 将 Docker 的卷安装在本地文件上来完成此操作。
因此,我拉取了 Alpine Docker 图像并开始使用它。由于 Alpine 镜像中没有 rename
命令,我使用 find
、mv
和 sed
:
1) 运行 来自 Alpine 镜像的容器,在 /tmp
中挂载我的本地目录,并在容器中启动一个 shell 会话:
docker run -ti -v `pwd`:/tmp alpine /bin/sh
2) 在容器内,运行重命名命令:
find /tmp -name '*.dic' | while read filename; do mv ${filename} $(echo ${filename} | sed -e 's/\.dic$/\.dcm/'); done
这工作正常,但我真正需要做的是启动容器,运行 命令,然后退出。所以我尝试了:
docker run -v `pwd`:/tmp alpine /bin/sh -c "find /tmp -name '*.dic' | while read filename; do mv ${filename} $(echo ${filename} | sed -e 's/\.dic$/\.dcm/'); done"
但它不起作用,文件未重命名,输出为:
BusyBox v1.28.4 (2018-05-30 10:45:57 UTC) multi-call binary.
Usage: mv [-fin] SOURCE DEST
or: mv [-fin] SOURCE... DIRECTORY
Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY
-f Don't prompt before overwriting
-i Interactive, prompt before overwrite
-n Don't overwrite an existing file
... 对找到的每个要重命名的文件重复一次。
我做错了什么?
遗憾的是 aplpine 没有重命名,加上复杂* bash 命令超过 docker cli 是一个奇怪的动物
我试了几次……但精神很好:)
试试这个:
docker run -v `pwd`:/tmp alpine /bin/sh -c "find /tmp -name '*.dic' -exec sh -c 'mv $"0" $"{0%.dic}".dcm' {} \;"
它不起作用的原因是因为使用双引号来包裹字符串意味着变量(例如${filename}
)被插值到 Alpine 外部 shell。您真正想要的是将字符串传递到单引号内的容器中,以便在容器内进行插值。
以下工作通过使用单引号字符串进行嵌套重命名,其中包含双引号字符串(与问题相反):
docker run -v pwd:/tmp alpine /bin/sh -c 'find /tmp -name "*.dic" | while read filename; do mv ${filename} $(echo ${filename} | sed -e "s/\.dic$/\.dcm/"); done'
然而,尽管这可行,但它并不是完美的解决方案。在执行的命令中保留使用单引号的另一种方法是将单引号包裹在双引号中并将其粘合到字符串中,例如“'”'s/find/replace/g'“'”。无数额外的引号和较低的易读性是否值得是 reader 的问题。那看起来像这样:
docker run -v pwd:/tmp alpine /bin/sh -c 'find /tmp -name '"'"'*.dic'"'"' | while read filename; do mv ${filename} $(echo ${filename} | sed -e '"'"'s/\.dic$/\.dcm/'"'"'); done'
TBH 我通常通过将命令放入脚本文件并将其包含在安装中来解决这种争论,因为脚本可以更容易地 shared/version 控制。