在bash中移动文件并自动重命名复制的文件而不覆盖现有文件的方法

3
我正在重构大量目录中的许多jpg文件,其中一些文件与其他目录中的文件同名。我想将文件移动/复制到其他目录,并在文件名与该目录中的另一个文件相匹配时,让bash自动将它们重命名(将IMG_238.jpg重命名为IMG_238_COPY1.jpg、IMG_238_COPY2.jpg等),而不是覆盖现有文件。
我已经编写了一个脚本,根据exif数据将jpg文件移动到新目录。将一个jpg文件移动的最后一行代码是:mv -n "$JPEGFILE" "$DIRNAME" 我使用-n选项,因为我不想覆盖文件,但现在我必须手动整理没有被移动/复制的文件。我的GUI可以自动完成这个任务...在bash中是否有相对简单的方法来实现此功能?
(如果有影响的话,我正在Mac OSX Lion中使用bash 3.2)

你使用的是哪个发行版,还是需要跨发行版? - Dan Fego
我正在使用带有bash 3.2的Mac OSX Lion。我会更新我的问题。 - Victor Van Hee
2
你可能想看一下 fdupes - 它可以帮助你摆脱重复的文件,这样你留下的任何未移动的文件都是真正不同的文件。 - holygeek
2个回答

5

这应该可以做到

# strip path, if any
fname="${JPEGFILE##*/}"
[ -f "$DIRNAME/$fname" ] && {
    n=1
    while [ -f "$DIRNAME/${fname%.*}_COPY${n}.${fname##*.}" ] ; do
        let n+=1
    done
    mv "$JPEGFILE" "$DIRNAME/${fname%.*}_COPY${n}.${fname##*.}"
} || mv "$JPEGFILE" "$DIRNAME"

编辑:改进。


你可以安全地删除第一个[ -f "$DIRNAME/$JPEGFILE" ] - holygeek
你也可以安全地删除尾部或“|| mv“$JPEGFILE”…” - holygeek
@holygeek:删除前导测试和备用mv将改变语义。我们不想在所有情况下都添加“_COPY $ {n}”,只有在需要时才添加。&& mv; mv是完全正确的,我在第一次重新阅读时就摆脱了它。 - sorpigal
2
抱歉,我的答案中有这个while条件:while [ -f "$DIRNAME/$JPEGFILE" ]; do ... 在你的答案出现之前,所以我想建议简化你的答案,而不是发布一个类似的答案。顺便说一下,如果$JPEGFILE有路径,那么mv "$fname" "$DIR..."看起来是错误的。 - holygeek
@holygeek:你说得对,那里的$fname是不正确的。应该是$JPEGFILE。已更正。 - sorpigal

2
您可以尝试下载并查看Ubuntu/Debian的基于Perl的rename是否可用。它具有sed风格的功能。引用一下man页面(在我的系统上,但脚本应该与链接的脚本相同):

"rename" renames the filenames supplied according to the rule specified as the first argument. The perlexpr argument is a Perl expression which is expected to modify the $_ string in Perl for at least some of the filenames specified. If a given filename is not modified by the expression, it will not be renamed. If no filenames are given on the command line, filenames will be read via standard input.

For example, to rename all files matching "*.bak" to strip the extension, you might say

    rename 's/\.bak$//' *.bak

To translate uppercase names to lower, you'd use

    rename 'y/A-Z/a-z/' *

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接