Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 27/01/2017, à 15:42

DonutMan75

[bash] Aspirer rapidement toutes les photos d'un disque dur

Bonjour à tous,
j'ai récemment été confronté au problème suivant : j'ai un vieux disque dur qui contient des photos de ci de là, je souhaitais toutes les récupérer rapidement sans avoir à explorer manuellement tous les (nombreux) sous-répertoires.

J'ai trouvé une solution avec la commande find de Linux et je me suis dit que j'allais partager ça avec vous smile
N'hésitez pas si vous avez des remarques ou des commentaires !

Dans la suite, je suppose que mes images peuvent avoir l'une des extensions suivantes : jpg, jpeg, JPG, JPEG
Je suppose que le répertoire racine où chercher mes images s'appelle "/chemin/a/traiter/" et le répertoire où copier mes images s'appelle "/chemin/de/backup/"

Voici ma commande

$ find -E /chemin/a/traiter/ -iregex '.*\.jpe?g' -exec cp {} /chemin/de/backup/ \;

Explications :

1) Construction de la regexp
Je veux un pattern qui matche les noms de fichier se terminant par .jpg, .jpeg, .JPG ou .JPEG
Ma regex en ERE (Extended Regular Expression) s'écrit : .*\.jpe?g
Cela signifie de gauche à droite :

  • n'importe quelle séquence de caractère : .*

  • suivi d'un point : \.

  • suivi des caractères j et p : jp

  • suivi d'un éventuel e : e?

  • suivi d'un g

2) Branchement de la regexp dans le find

Cette regexp utilisant le méta-caractère '?' qui est défini dans les ERE, il faut que je dise implicitement à find d'utiliser ces types de regex, c'est le rôle de l'option -E
Au final on a donc :

$ find -E /chemin/a/traiter/ -iregex '.*\.jpe?g'

L'option -iregex remplace ici l'habituel -name et permet d'utiliser une regexp et d'être insensible à la casse. Remarquons au passage que toto.jPeG sera également retenu par le filtre, mais ça n'est pas bien grave...

A ce niveau de la commande, nous sommes en mesure de lister l'ensemble des photos présentes dans le répertoire à traiter. Il nous reste à copier ces fichiers vers le répertoire cible.

3) Copier des photos vers le répertoire cible

C'ets le rôle de l'option -exec dont le prototype est le suivant :

$ find <blablabla> -exec ma_commande {} \;

Ici la séquence {} sera remplacée itérativement par chaque valeur trouvée dans find.
Ainsi si mon find trouve 3 images a.jpg, b.JPG et c.jpeg, il lancera ma_commande 3 fois :

$ ma_commande a.jpg
$ ma_commande b.JPG
$ ma_commande c.jpeg

La séquence \; sert à marquer la fin de l'instruction -exec. A noter que si on remplace \; par + alors ma_commande est lancée une seule fois avec tous les arguments à la suite. Dans notre exemple, ça donnerait donc

$ ma_commande a.jpg b.JPG c.jpeg

Ici c'est bien le comportement itératif qui nous intéresse. On remplace ma_commande par cp et on spécifie le répertoire de sortie, ce qui donne notre commande finale :

$ find -E /chemin/a/traiter/ -iregex '.*\.jpe?g' -exec cp {} /chemin/de/backup/ \;

L'inconvénient de cette solution est qu'on perd *complètement* l'arborescence de nos photos : tout est écrit en plat. Mais au moins on est sûr d'être exhaustif smile

Bonne aprem et à bientôt smile

Donut.

Hors ligne

#2 Le 27/01/2017, à 15:56

Brunod

Re : [bash] Aspirer rapidement toutes les photos d'un disque dur

Salut,
Question subsidiaire : quid si deux photos différentes de répertoires différents portent le même nom ?


Windows est un système d'exploitation de l'homme par l'ordinateur. Linux, c'est le contraire...
39 pc linux convertis

Hors ligne

#3 Le 27/01/2017, à 16:49

DonutMan75

Re : [bash] Aspirer rapidement toutes les photos d'un disque dur

Ah purée, excellente remarque !
Je dirais que d'après le comportement par défaut de cp, les fichiers s'écraseront les uns après les autres...
On peut rajouter l'option -i pour avertir l'utilisateur d'un possible overwrite... je cherche dans les options de cp mais a priori il n'y a rien qui permette de rajouter un "_01" automatique et incrémental à la fin du fichier en question....
Comment s'en sortir sans trop alourdir la commande ? Vous avez des idées ?

Donut.

Hors ligne

#4 Le 27/01/2017, à 17:27

DonutMan75

Re : [bash] Aspirer rapidement toutes les photos d'un disque dur

Bon en farfouillant un peu, j'ai trouvé l'option --backup qui permet de sauvegarder les éventuelles cibles déjà présentes.
Au passage, la commande que j'ai donnée pour find fonctionne très bien sous Mac mais pas sous Ubuntu où il faut changer le find -E en find -regextype posix-extended.

Au final j'obtiens :

$ find . -regextype posix-extended -iregex '.*\.jpe?g' -exec cp --backup='numbered' {} ../exit/ \;

Si mon fichier a.jpg est présent dans 3 sous-répertoires différents, j'obtiens en sortie les fichiers a.jpg a.jpg.~1~ et a.jpg.~2~

Problème : ces fichiers n'apparaissent pas dans mon navigateur, ce n'est pas très agréable.... J'ai essayé l'option --sufix='_' sans succès.... Avez-vous des idées ?

Donut.

Hors ligne

#5 Le 27/01/2017, à 17:33

Brunod

Re : [bash] Aspirer rapidement toutes les photos d'un disque dur

C'est vraisemblablement lié au suffixe qui modifie l'extension. Il faut garder le .jpg pour finir, peut-être mettre nom[1].jpg, nom[2].jpg, ... Ne pas utiliser les () qui sont déjà employées par le système en cas de doublons.
Bon amusement. smile


Windows est un système d'exploitation de l'homme par l'ordinateur. Linux, c'est le contraire...
39 pc linux convertis

Hors ligne

#6 Le 27/01/2017, à 17:45

DonutMan75

Re : [bash] Aspirer rapidement toutes les photos d'un disque dur

Par ailleurs, je me rends compte que des fichiers .toto.jpg sont crées automatiquement pour chaque fichier toto.jpg existant... Je suppose qu'il s'agit des miniatures affichées dans nautilus ? (ou dans MacOS ???)

Afin de ne pas les prendre en compte dans mon script j'ai modifié ma regex pour les exclure. J'obtiens au final :

$ find . -regextype posix-extended -iregex '(.*/)?[^.][^/]*\.jpe?g'

On dépiaute tout ça :

  • (.*/)? : présence éventuelle d'un chemin (se terminant donc logiquement par un '/')

  • [^.] : ce qui suit est tout ce qu'on veut sauf un point

  • [^/]* : le nom du fichier proprement dit. par rapport à tout à l'heure, on exclut cette fois-ci les '/' dans le nom du fichier

  • *\.jpe?g : notre fameux .jpg, .jpeg, .JPG, .JPEG de tout à l'heure

Néanmoins, je bute toujours sur la copie non-destructive avec un incrément propre et contrôlé.
Un truc du genre :
a.jpg
a_01.jpg
a_02.jpg
etc...

Vous avez des idées ?

Merci d'avance smile

Donut

EDIT : merci Brunod, je viens de voir ta réponse, nos messages se sont croisés smile Je regarde ça et je vous tiens au courant !

Dernière modification par DonutMan75 (Le 27/01/2017, à 17:46)

Hors ligne

#7 Le 27/01/2017, à 18:06

DonutMan75

Re : [bash] Aspirer rapidement toutes les photos d'un disque dur

Bon...

Le man de cp indique :

The   backup   suffix   is  `~',  unless  set  with  --suffix  or  SIM‐
       PLE_BACKUP_SUFFIX.  The version control method may be selected via  the
       --backup  option  or  through the VERSION_CONTROL environment variable.

Néanmoins --suffix='_' ou avoir une variable SIMPLE_BACKUP_SUFFIX='_' n'a AUCUNE INCIDENCE lorsque --backup='numbered' ou --backup='t'

Je crois comprendre que le suffixe ne peut être changé que dans le cas de l'overwrite simple (i.e. une ou aucune occurence possible)... Dans le cas contraire (i.e. numbered) alors le comportement par défaut (à savoir ajouter des .~1~, .~2~, .~3~ etc... à la fin des fichiers redondants) n'est pas modifiable.......

Qu'en dites-vous ?

L'un d'entre vous a-t'il déjà rencontré ce problème ?

Merci d'avance

Donut

Hors ligne