#1 Le 27/01/2017, à 14: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
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
Bonne aprem et à bientôt
Donut.
Hors ligne
#2 Le 27/01/2017, à 14: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, à 15: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, à 16: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, à 16: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.
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, à 16: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
Donut
EDIT : merci Brunod, je viens de voir ta réponse, nos messages se sont croisés Je regarde ça et je vous tiens au courant !
Dernière modification par DonutMan75 (Le 27/01/2017, à 16:46)
Hors ligne
#7 Le 27/01/2017, à 17: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