bash: усекать имена файлов, сохраняя их уникальность - PullRequest
5 голосов
/ 09 января 2011

Я использую цикл 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 и все имена уже заняты, он должен заменить последние ДВА символа «Shortname» на «10» и проверить, существует ли этот файл.

Пример: допустим, у меня есть каталог со следующими файлами:

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

Не имеет значения, переименовано ли «MyTerriblyLongLongFourteenFile.jpg» в «MyTerriblyLong14.jpg», это зависит от алфавитной сортировки. Просто важно, чтобы каждый из них получил уникальное имя.

Каков наилучший способ сделать это?

1 Ответ

4 голосов
/ 09 января 2011

Попробуйте это сначала на тестовых файлах.Обычный метод тестирования с использованием 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
...