使用Docker Alpine在本地文件上运行Shell命令

时间:2018-07-10 08:44:48

标签: shell docker busybox alpine

我的目录中充满了扩展名为.dic的文件,我需要(递归地)重命名它们以拥有扩展名.dcm。但是,我需要通过运行将卷安装在本地文件上的Docker来执行此操作。

因此,我提取了Alpine Docker映像并开始使用它。由于Alpine图片中没有rename命令,因此我使用findmvsed

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

...对每个要重命名的文件重复一次。

我做错了什么?

2 个答案:

答案 0 :(得分:3)

之所以不起作用,是因为使用双引号将字符串包装起来意味着变量(例如${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'

但是,尽管这可行,但这并不是完美的解决方案。在执行的命令中保留使用单引号的另一种方法是将单引号括在双引号中并将其粘贴到字符串中,例如“'”的/查找/替换/ g'“'”。大量的额外报价和较低的可读性是否值得,这是读者的一个问题。看起来像这样:

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我通常通过将命令拖放到脚本文件中并将其包含在安装文件中来避免这种麻烦,因为脚本可以比以前更容易共享/版本控制。

答案 1 :(得分:1)

悲伤的aplpine没有重命名,加上在docker cli上使用复杂的bash命令是一种奇怪的动物

给我做了几次尝试...但是精神上很不错:)
试试这个:

docker run -v `pwd`:/tmp  alpine /bin/sh -c "find /tmp -name '*.dic' -exec sh -c 'mv $"0" $"{0%.dic}".dcm'  {} \;"