Правильные расширения файлов

15

У меня есть около 12000 изображений разных типов файлов, но каждое из них было переименовано в * .jpg.

Теперь я хочу дать им их правильные расширения обратно, как я могу это сделать

akabhirav
источник
2
рекурсивно или в "плоском" каталоге?
Джейкоб Влейм
1
@steeldriver довольно близко, но эти файлы не имеют расширения, здесь они имеют неправильное расширение.
Джейкоб Влейм
1
@JacobVlijm, поэтому я не пометил вопрос как дубликат: однако методы, предложенные в ответах, имеют здесь значение, ИМХО
steeldriver
@steeldriver Я полностью согласен.
Джейкоб Влийм

Ответы:

22

Вы можете сделать это относительно легко в bash:

for f in *jpg; do 
    type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+') 
    mv "$f" "${f%%.*}.${type,,}"  
done

Это та же идея, что и в ответе @ AB, но вместо глобуса используются оболочки find. Это ${f%%.*}имя файла без его расширения. Команда -0of fileзаставляет печатать \0после имени файла, которое мы затем используем для grepтипа файла. Это должно работать с произвольными именами файлов, включая те, которые содержат пробелы, переводы строки или что-либо еще. Это ${type,,}хитрость, чтобы получить расширения нижнего регистра. Это будет преобразовано PNGв png.

Вы не сказали в своем вопросе, но если вам нужно, чтобы это было рекурсивным и переходило в подкаталоги, вы можете использовать это вместо этого:

shopt -s globstar
for f in **/*jpg; do 
    type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+') 
    mv "$f" "${f%%.*}.${type,,}"  
done

shopt -s globstarБудет включить опцию globstar Баша, который позволяет **матч подкаталогов:

globstar

Если установлено, шаблон **, используемый в контексте расширения имени пути, будет соответствовать всем файлам и нулю или более каталогов и подкаталогов. Если за шаблоном следует символ /, совпадут только каталоги и подкаталоги.

terdon
источник
@AB см. Обновление. Это позволяет **переходить в подкаталоги.
тердон
Эти точки с запятой в конце каждой строки избыточны, не так ли?
Пэдди Ландау
@PaddyLandau да, я тестировал его как один лайнер и добавил новые строки для ясности здесь. Я забыл удалить их. Обратите внимание, что они не ошибаются, просто избыточны, как вы говорите.
тердон
Отлично, хотя fileне всегда указывает расширение, которое кажется: оно превращает bash-файл foo.bourne-againсюда, например!
Кампа
1
@ Кампы нет, конечно нет. Это также добавит поддельные расширения в двоичные файлы, обычные текстовые файлы, сценарии Perl и Python, и этот список можно продолжить. Вопрос задавался именно об изображениях, и они, как правило, имеют то же имя, что и их обычные расширения. Помните, что расширения в Linux являются необязательными, за очень немногими исключениями, они на самом деле ничего не делают. Они помогают пользователю организовать свои данные, ОС не заботится о них.
тердон
11

Сценарий ниже может быть использован (рекурсивно) для переименования неправильно установленного расширения .jpgв правильное. Если он обнаружит нечитаемый файл, он сообщит об этом в выводе скрипта.

Сценарий использовать imghdrмодуль, чтобы распознавать следующие типы: rgb, gif, pbm, pgm, ppm, tiff, rast, xbm, jpeg, bmp, png. Подробнее о imghdrмодуле здесь . Список может быть расширен за счет большего количества типов, как указано в ссылке.

Как таковой, он специально переименовывает файлы с расширением .jpg, как указано в вопросе. С небольшим изменением можно переименовать любое расширение или определенный набор расширений в правильное (или без расширения, как здесь ).

Сценарий:

#!/usr/bin/env python3
import os
import imghdr
import shutil
import sys

directory = sys.argv[1]

for root, dirs, files in os.walk(directory):
    for name in files:
        file = root+"/"+name
        # find files with the (incorrect) extension to rename
        if name.endswith(".jpg"):
            # find the correct extension
            ftype = imghdr.what(file)
            # rename the file
            if ftype != None:
                shutil.move(file, file.replace("jpg",ftype))
            # in case it can't be determined, mention it in the output
            else:
                print("could not determine: "+file)

Как пользоваться

  1. Скопируйте скрипт в пустой файл, сохраните его как rename.py
  2. Запустите его командой:

    python3 /path/to/rename.py <directory>
    
Якоб Влейм
источник
+1 для простых и легко читаемых, в отличие от решений на основе bash.
Давиде
3

Примечание: мой подход кажется слишком сложным. Я бы предпочел, чтобы тердоны ответили на вашем месте.


Вы можете использовать команду fileдля определения типа файла:

% file 20050101_14-24-37_330.jpg 
20050101_14-24-37_330.jpg: JPEG image data, EXIF standard 2.2, baseline, precision 8, 1200x1600, frames 3

% file test.jpg
test.jpg: PNG image data, 1192 x 774, 8-bit/color RGBA, non-interlaced

С этой информацией файлы могут быть переименованы:

Пожалуйста, сделайте тест, прежде чем применять команду к вашим изображениям

find . -type f -iname "*.jpg" -print0 | xargs -0 -I{} file -F"<separator>" {} | 
 awk -F " image data" '{print $1}' | 
  awk -F"<separator> " '{
   system("mv \""$1"\" $(dirname \""$1"\")/$(basename -s .jpg \"" $1 "\")."$2)
   }'

пример

% find . -type f -name "*.jpg"
./test.jpg
./sub/20050101_14-24-37_330.jpg

% find . -type f -iname "*.jpg" -print0 | xargs -0 -I{} file -F"<separator>" {} | awk -F " image data" '{print $1}' | awk -F"<separator> " '{system ("mv \""$1"\" $(dirname \""$1"\")/$(basename -s .jpg \"" $1 "\")."$2)}'

% find . -type f -iname "*"    
./test.PNG
./sub/20050101_14-24-37_330.JPEG
AB
источник
Обратите внимание, что это сломается в маловероятном случае, если любое имя файла содержит символы новой строки.
тердон
@terdon Да, я думал. К сожалению, я понятия не имею, что я могу сделать. Вы можете помочь?
АВ
Я понятия не имею, как сделать это правильно с помощью awk. Это не правильный инструмент для работы. Либо используйте find -exec bash -c "..."и делайте все там, либо используйте, while read -d '' name typeчтобы разделить имя файла и fileвывод, а затем проанализировать, $typeчтобы получить тип файла. На самом деле не стоит, смотрите мой ответ о том, как сделать это намного проще в чистом (ish) bash.
тердон