2015-03-05 2 views
0

У меня есть много файлов для переименования. Почти все эти файлы - это картинки.Извлечение последнего номера из имени файла в Bash

Источником имен файлов являются чем-то вроде:

DSC08828.JPG  => 08828.JPG 
20130412_0001.JPG => 0001.JPG 
0002.JPG   => 0002.JPG 
IMG0047.jpg  => 0047.jpg 
DSC08828_1.JPG  => Is a duplicate should be ignored 
... 
DSC08828_9.JPG  => Is a duplicate should be ignored 

Все, что я хочу сделать, это получить последний номер с последующим расширением файла таким образом, что это так быстро, как это возможно (как мы говорим о почти 600.000 Pictures)

Так что я хочу получить строку из первого появления по крайней мере двух цифр справа после точки до первого символа без номера. Если справа есть только одна цифра, файл следует игнорировать.

+0

Спасибо. Это было быстро! Все ваши решения дают неплохие результаты при адаптации к моему сценарию. Мне нравится это сообщество. – Tobi

ответ

1

Вот метод, использующий sed, который может улучшить производительность:

ls *.{JPG,jpg} | \ 
sed ' 
    /_[1-9]*\./d; # first drop any line that appears to be a duplicate 
    /^[0-9]*\./d; # drop any line that does not need to be renamed 
    s/\(.*\)/\1 \1/; # save the original filename by duplicating the pattern space 
    s/ .*_/ /;  # remove any leading characters followed by and including _ in the new filename 
    s/ [A-Z]*/ /; # remove any leading capital letters from the new filename 
    s/^/mv -i /;  # finally insert mv command at the beginning of the line 
' 

Когда вы будете удовлетворены с помощью команд, кормить sh.

Вход:

0002.JPG 
20130412_0001.JPG 
DSC08828.JPG 
DSC08828_1.JPG 
DSC08828_9.JPG 
IMG0047.jpg 

Выход:

mv -i 20130412_0001.JPG 0001.JPG 
mv -i DSC08828.JPG 08828.JPG 
mv -i IMG0047.jpg 0047.jpg 
+1

Это наверняка сбой с 600000 файлами, так как вы превысите максимальную длину командной строки: на моей машине 'getconf ARG_MAX' выдает' 2097152', а файлы имеют не менее 5 символов, поэтому с 600000 файлами это уже превышены. Кроме того, [не анализируйте вывод 'ls'] (http://mywiki.wooledge.org/ParsingLs). Особенно, здесь, вы _really_ не нужны 'ls'! посмотрите на свою команду 'ls *. {JPG, jpg}': сначала оболочка видит скобу и расширяет ее; он оставлен с 'ls * .JPG * .jpg'; он затем выполняет расширение пути и пытается передать это 'ls'! это бесполезно! –

+2

Что будет с этим делать? он сортирует аргументы и выводит их. Вы могли бы просто сделать: 'printf '% s \ n' *. {JPG, jpg}'. Теперь глобусы медленны в оболочках, поэтому метод с использованием 'find' будет более уместным. –

+0

Ответ на базовый вопрос о том, как получить новое имя файла. Я перебираю файлы в папках (одна папка в день). Структура: 2013/12/31/BildXXXX.jpg и поместите их в новую структуру с новыми именами. – Tobi

1
for x in ./*.JPG ./*.jpg; do 
    y=$(echo "$x"|sed '/[^0-9]//g'); 
    echo "$x" "$y"; 
done 

В то время как я не даю вам окончательный ответ на плите, это должно вам начать и продемонстрировать технику, как подойти к задачам, которые вы описали.

В зависимости от того, что вы хотите делать с файлами после этого, вы можете также комбинировать find и grep, такие как find . -type f | grep -v '_[0-9]\.' фильтровать все файлы, содержащие _ следуют одной цифре, за одну точку (не тестировалось, спасаясь может потребоваться). -v используется для отрицания совпадений, отфильтрованных grep.

Поскольку в вашем посте вы сказали, что хотите переименовать фильтр И предоставили пример, где вы фильтруете некоторые файлы, я предполагаю, что вам понадобятся оба: сначала, фильтровать файлы, которые вы не хотите, а затем переименовать фильтрованных в петле for.

1
sed -nr 's%^.*[^0-9]([0-9]{2,}\.[^.]+)$%\1%p' < <(find ./ -type f -iname '*.JPG') 

SED резко быстрее, чем BASH при обработке регулярных выражений, поэтому используйте его вместо = ~, когда это возможно.

Смежные вопросы