bash:截断文件名,使它们保持唯一

时间:2011-01-09 08:36:59

标签: bash filenames truncate renaming

我正在使用与此类似的for循环将文件夹中的所有文件名截断为16个字符:

for i in *; do
    Shortname=${i:0:16}     # Let's assume I don't need the extension
    mv "$i" "$Shortname"
done

问题是:每当两个文件名具有相同的前16个字符时,后一个将覆盖前一个(在OS X mv上就是这样)。

如何检查名称为“Shortname”的文件是否已存在,如果存在,请将“Shortname”的最后一个字符替换为数字。然后再次检查是否存在具有该名称的文件,如果存在,请尝试更高的数字。等等。如果它到达第9号并且到目前为止所有名字都被取走了,它应该用“10”替换“Shortname”的最后两个字符并检查该文件是否已经存在。

示例:假设我有一个包含以下文件的目录:

MyTerriblyLongLongFirstFile.jpg
MyTerriblyLongLongSecondFile.jpg
MyTerriblyLongLongThirdFile.jpg
...
MyTerriblyLongLongFourteenthFile.jpg
...
MyTerriblyLongLongOneHundredSixtySeventhFile.jpg
...
MyTerriblyLongLongFiveMillionthFile.jpg

请注意,所有文件的前16个字母都相同。运行脚本后,我希望将它们重命名为:

MyTerriblyLongL1.jpg
MyTerriblyLongL2.jpg
MyTerriblyLongL3.jpg
...
MyTerriblyLong14.jpg
...
MyTerriblyLon167.jpg
...
MyTerribl5000000.jpg

将“MyTerriblyLongLongFourteenthFile.jpg”重命名为“MyTerriblyLong14.jpg”并不重要,这取决于字母排序。他们每个人都有一个独特的名字,这一点非常重要。

这样做的最佳方式是什么?

1 个答案:

答案 0 :(得分:4)

首先在测试文件上尝试此操作。使用echo代替mv进行测试的常用方法不会告诉您太多,因为不会创建潜在的名称冲突。

#!/bin/bash
num=1
length=16
for file in M*.jpg
do
    newname=$file
    until [[ ! -f $newname ]]
    do
        (( sublen = length - ${#num} ))
        printf -v newname '%.*s%d' "$sublen" "$file" "$num"
        (( num++ ))
    done
    mv "$file" "$newname"
done

测试:

$ touch MyTerriblyLongLongFilenames{a..k}.jpg
$ touch MyTerriblyLongL3
$ ls M*
MyTerriblyLongL3                  MyTerriblyLongLongFilenamesf.jpg
MyTerriblyLongLongFilenamesa.jpg  MyTerriblyLongLongFilenamesg.jpg
MyTerriblyLongLongFilenamesb.jpg  MyTerriblyLongLongFilenamesh.jpg
MyTerriblyLongLongFilenamesc.jpg  MyTerriblyLongLongFilenamesi.jpg
MyTerriblyLongLongFilenamesd.jpg  MyTerriblyLongLongFilenamesj.jpg
MyTerriblyLongLongFilenamese.jpg  MyTerriblyLongLongFilenamesk.jpg
$ ./nocollide
$ ls M*
MyTerriblyLong10  MyTerriblyLongL1  MyTerriblyLongL4  MyTerriblyLongL7
MyTerriblyLong11  MyTerriblyLongL2  MyTerriblyLongL5  MyTerriblyLongL8
MyTerriblyLong12  MyTerriblyLongL3  MyTerriblyLongL6  MyTerriblyLongL9