Extensions de fichier correctes

15

J'ai environ 12000 images de différents types de fichiers, mais chacune d'elles a été renommée * .jpg.

Maintenant, je veux leur rendre leurs extensions appropriées, comment puis-je le faire

akabhirav
la source
2
récursivement, ou dans un répertoire "plat"?
Jacob Vlijm
1
@steeldriver assez proche, mais ces fichiers n'ont pas d'extension, ici ils ont la mauvaise extension.
Jacob Vlijm
1
@JacobVlijm c'est pourquoi je n'ai pas signalé la question en double: cependant les méthodes proposées dans les réponses ont de la valeur ici, à
mon humble avis
@steeldriver Je suis entièrement d'accord.
Jacob Vlijm

Réponses:

22

Vous pouvez le faire relativement facilement en bash:

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

C'est la même idée que la réponse de @ AB mais en utilisant des globes shell à la place de find. Le ${f%%.*}est le nom du fichier sans son extension. La -0de la filecommande permet d' imprimer un \0après le nom de fichier que nous utilisons ensuite greple type de fichier. Cela devrait fonctionner avec des noms de fichiers arbitraires, y compris ceux qui contiennent des espaces, des retours à la ligne ou toute autre chose. C'est ${type,,}une astuce pour obtenir des extensions minuscules. Il se convertirait PNGen png.

Vous n'avez pas dit dans votre question, mais si vous avez besoin que cela soit récursif et descende dans des sous-répertoires, vous pouvez l'utiliser à la place:

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

L' shopt -s globstaractivera l'option globstar de bash qui permet de faire **correspondre les sous-répertoires:

globstar

S'il est défini, le modèle ** utilisé dans un contexte d'extension de chemin correspondra à tous les fichiers et à zéro ou plusieurs répertoires et sous-répertoires. Si le modèle est suivi d'un /, seuls les répertoires et sous-répertoires correspondent.

terdon
la source
@AB voir la mise à jour. Il permet **de rentrer dans des sous-répertoires.
terdon
Ces points-virgules à la fin de chaque ligne sont redondants, n'est-ce pas?
Paddy Landau
@PaddyLandau oui, je le testais comme une ligne et j'ai ajouté des nouvelles lignes pour plus de clarté ici. J'ai oublié de les supprimer. Notez qu'ils ne se trompent pas, juste redondants comme vous le dites.
terdon
Génial, bien filequ'il ne spécifie pas toujours l'extension qu'il semble: il transforme un fichier bash foo.bourne-againici par exemple!
Campa
1
@Campa non, bien sûr que non. Il ajouterait également de fausses extensions aux fichiers binaires, aux fichiers texte normaux, aux scripts perl et python et la liste s'allonge. La question portait sur les images en particulier et celles-ci ont généralement le même nom que leurs extensions habituelles. N'oubliez pas que les extensions sous Linux sont facultatives, à quelques exceptions près, elles ne font rien. Ils aident l'utilisateur à organiser ses données, le système d'exploitation ne se soucie pas d'eux.
terdon
11

Le script ci-dessous peut être utilisé pour (récursivement) renommer une extension incorrectement définie,, .jpgpar la bonne. S'il trouve un fichier illisible, il le signalera dans la sortie du script.

Le script utilise le imghdrmodule, pour reconnaître les types suivants: rgb, gif, pbm, pgm, ppm, tiff, rast, xbm, jpeg, bmp, png. Plus d'informations sur le imghdrmodule ici . La liste peut être étendue avec plus de types, comme mentionné dans le lien.

En l'état, il renomme spécifiquement les fichiers avec l'extension .jpg, comme mentionné dans la question. Avec un changement mineur, il peut être approprié de renommer n'importe quelle extension, ou un ensemble spécifique d'extensions, en la bonne (ou sans extension, comme ici ).

Le script:

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

Comment utiliser

  1. Copiez le script dans un fichier vide, enregistrez-le sous rename.py
  2. Exécutez-le par la commande:

    python3 /path/to/rename.py <directory>
    
Jacob Vlijm
la source
+1 pour une lecture simple et facile, contrairement aux solutions basées sur bash.
Davide
3

Remarque: Mon approche semble être trop complexe. Je préférerais que les terdons répondent à votre place.


Vous pouvez utiliser la commande filepour déterminer le type de fichier:

% 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

Avec ces informations, les fichiers peuvent être renommés:

Veuillez faire un test avant d'appliquer la commande à vos images

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

Exemple

% 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
UN B
la source
Notez que cela se cassera dans le cas peu probable où l'un des noms de fichier contiendrait des retours à la ligne.
terdon
@terdon Oui, j'ai réfléchi. Malheureusement, je n'ai aucune idée de ce que je peux faire. Pouvez-vous m'aider?
AB
Je ne sais pas comment faire cela correctement en utilisant awk. Ce n'est pas le bon outil pour le travail. Soit utiliser find -exec bash -c "..."et tout faire là-dedans, soit utiliser while read -d '' name typepour diviser le nom de fichier et la filesortie, puis analyser $typepour obtenir le type de fichier. Ça ne vaut pas vraiment le coup, voir ma réponse pour savoir comment le faire beaucoup plus facilement en pure (ish) bash.
terdon