Prawidłowe rozszerzenia plików

15

Mam około 12000 obrazów różnych typów plików, ale każdy z nich został przemianowany na * .jpg.

Teraz chcę przywrócić im odpowiednie rozszerzenia, jak mogę to zrobić

akxer
źródło
2
rekurencyjnie, czy w „płaskim” katalogu?
Jacob Vlijm
1
@steeldriver dość blisko, ale te pliki nie mają rozszerzenia, tutaj mają nieprawidłowe rozszerzenie.
Jacob Vlijm
1
@JacobVlijm, dlatego nie zgłosiłem pytania jako duplikatu: jednak metody zaproponowane w odpowiedziach mają tutaj wartość, IMHO
steeldriver
@steeldriver Całkowicie się zgadzam.
Jacob Vlijm

Odpowiedzi:

22

Możesz to zrobić stosunkowo łatwo w bash:

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

Jest to ten sam pomysł, co odpowiedź @ AB, ale zamiast tego używa się globów powłoki find. Jest ${f%%.*}to nazwa pliku bez rozszerzenia. -0Z filepoleceniem czyni go wydrukować \0po nazwie pliku, który używamy do greptypu pliku. Powinno to działać z dowolnymi nazwami plików, w tym zawierającymi spacje, znaki nowej linii lub cokolwiek innego. ${type,,}To podstęp, aby uzyskać niższe rozszerzenia przypadków. Przekształciłby PNGsię w png.

Nie powiedziałeś w swoim pytaniu, ale jeśli potrzebujesz tego, aby być rekurencyjnym i zejść do podkatalogów, możesz użyć tego w zamian:

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 globstarPozwoli opcję globstar bash, który pozwala **podkatalogi meczu:

globstar

Jeśli jest ustawiony, wzorzec ** użyty w kontekście rozszerzenia nazwy ścieżki będzie pasował do wszystkich plików i zero lub więcej katalogów i podkatalogów. Jeśli po wzorcu występuje znak /, tylko katalogi i podkatalogi są zgodne.

terdon
źródło
@AB zobacz aktualizację. Pozwala to **na ponowne przechodzenie do podkatalogów.
terdon
Te średniki na końcu każdej linii są zbędne, prawda?
Paddy Landau
@PaddyLandau tak, testowałem to jako linijkę i dodałem tutaj nowe linie dla przejrzystości. Zapomniałem je usunąć. Pamiętaj, że nie są w błędzie, są po prostu zbędne, jak mówisz.
terdon
Świetnie, choć filenie zawsze wydaje się, jakie rozszerzenie wydaje się: na przykład zmienia tutaj plik bash foo.bourne-again!
Campa,
1
@Campa nie, oczywiście że nie. Dodałby także fałszywe rozszerzenia do plików binarnych, normalnych plików tekstowych, skryptów perl i python, a lista jest długa. Pytanie dotyczyło konkretnie obrazów, które zazwyczaj mają takie same nazwy jak ich zwykłe rozszerzenia. Pamiętaj, że rozszerzenia w systemie Linux są opcjonalne, z nielicznymi wyjątkami, w rzeczywistości nic nie robią. Pomagają użytkownikowi uporządkować dane, system operacyjny nie dba o nie.
terdon
11

Poniższego skryptu można użyć do (rekurencyjnej) zmiany nazwy nieprawidłowo ustawionego rozszerzenia .jpgna prawidłowe. W przypadku znalezienia nieczytelnego pliku zgłosi go w danych wyjściowych skryptu.

Skrypt użyć imghdrmodułu rozpoznawania następujących typów: rgb, gif, pbm, pgm, ppm, tiff, rast, xbm, jpeg, bmp, png. Więcej o imghdrmodule tutaj . Lista może zostać rozszerzona o więcej typów, jak wspomniano w linku.

W tej chwili zmienia nazwy plików z rozszerzeniem .jpg, jak wspomniano w pytaniu. Po niewielkiej zmianie można zmienić nazwę dowolnego rozszerzenia lub określonego zestawu rozszerzeń na prawidłowe (lub bez rozszerzenia, jak tutaj ).

Scenariusz:

#!/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)

Jak używać

  1. Skopiuj skrypt do pustego pliku i zapisz go jako rename.py
  2. Uruchom go za pomocą polecenia:

    python3 /path/to/rename.py <directory>
    
Jacob Vlijm
źródło
+1 za proste i łatwe do odczytania, w przeciwieństwie do rozwiązań opartych na bash.
Davide
3

Uwaga: moje podejście wydaje się zbyt skomplikowane. Wolałbym, żeby terdons odpowiedział na twoim miejscu.


Możesz użyć polecenia, fileaby określić typ pliku:

% 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

Dzięki tym informacjom można zmienić nazwę plików:

Wykonaj test, zanim zastosujesz polecenie do swoich zdjęć

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)
   }'

Przykład

% 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
źródło
Pamiętaj, że spowoduje to uszkodzenie w mało prawdopodobnym przypadku, gdy dowolna nazwa pliku zawiera znaki nowej linii.
terdon
@terdon Tak, myślałem. Niestety nie mam pojęcia, co mogę zrobić. Możesz pomóc?
AB
Nie mam pojęcia, jak to zrobić poprawnie za pomocą awk. To nie jest odpowiednie narzędzie do pracy. Użyj albo find -exec bash -c "..."zrób wszystko, co tam jest, albo użyj, while read -d '' name typeaby podzielić nazwę pliku i filedane wyjściowe, a następnie parsuj, $typeaby uzyskać typ pliku. Naprawdę nie warto, zobacz moją odpowiedź, jak to zrobić o wiele łatwiej w czystym (ish) bashu.
terdon