从多目录批量复制文件并生成带指定前缀的两份副本
多目录下批量生成带前缀文件副本的解决方案
先说说你之前命令出错的原因
你用find | xargs的写法踩了两个常见的坑:
- xargs的逻辑不匹配:xargs会把find找到的所有文件一次性丢给
cp,但cp如果要复制多个文件,最后一个参数必须是目标目录。你的命令里写的"prefix-$file"根本没意义——因为$file这个变量在xargs的上下文里根本不存在,xargs会把所有找到的文件都当作源,最后一个文件被误当成目标目录,所以才会报“不是目录”的错误。 - 变量作用域问题:
$file是你之前单目录for循环里的变量,管道后面的shell进程看不到这个变量,相当于你在给cp传一个空值的目标,逻辑完全走偏了。
正确的命令实现
用find的-exec选项就能完美解决这个问题,它可以对每个找到的文件单独执行处理逻辑,刚好满足你要生成两份副本的需求。直接用下面的命令就行:
find . -type f \( -iname "*.jpg" ! -iname "special-*.jpg" \) -exec sh -c ' for file do # 生成第一份带prefix-01前缀的副本 cp -v "$file" "${file%/*}/prefix-01-${file##*/}" # 生成第二份带prefix-02前缀的副本 cp -v "$file" "${file%/*}/prefix-02-${file##*/}" done ' sh {} +
逐行解释下这个命令
find . -type f \( -iname "*.jpg" ! -iname "special-*.jpg" \):遍历当前目录下所有.jpg文件,同时排除文件名以special-开头的文件,这部分和你之前的逻辑一致。-exec sh -c '...' sh {} +:把找到的文件批量传给后面的小shell脚本处理,sh {} +是标准用法,{}会被替换成找到的所有文件列表。${file%/*}:这是shell的参数扩展,用来提取文件所在的目录路径(比如./Sub-Directory-name-01/filename-01.jpg会被处理成./Sub-Directory-name-01)。${file##*/}:同样是参数扩展,用来提取纯文件名(比如上面的路径会被处理成filename-01.jpg)。- 拼接之后,副本的路径就是
原文件所在目录/prefix-xx-原文件名.jpg,刚好满足“副本保存在原文件子目录”的要求。
效果验证
执行完这个命令后,每个符合条件的原文件都会在同一个子目录下生成两个副本:
比如Sub-Directory-name-01/filename-01.jpg会生成:
Sub-Directory-name-01/prefix-01-filename-01.jpgSub-Directory-name-01/prefix-02-filename-01.jpg
而且原文件会完整保留,完全符合你的所有需求。
内容的提问来源于stack exchange,提问作者Newbies
相关产品推荐
相关产品推荐

