#!/bin/bash # http://nicofo.tuxfamily.org # 21/10/06 : v1 : version de base - photos uniquement (renamePhotos) # 10/12/06 : v2 : tout type de fichier (renomme) # 17/03/07 : v3 : ajout option --comment # 30/04/07 : v4 : ajout option --addComment|-a # 07/09/07 : v5 : ajout addComment sur une seule photo # 16/10/08 : v6 : ajout option -i # 06/09/09 : v7 : diaporama : ajout options --dHP / --dCANON # 10/10/09 : v8 : fusion avec le script 'datePhotos' (-d|--date), ajout --undo et --diapo # nouvelle version addComment (-a), ajout supComment (-s) # 03/01/10 : v8.1 : ajout de "TMPTMP" pour toutes les photos # 28/02/10 : v8.2 : correction bug avec variable 'index' => 'index_com' # 13/05/10 : v8.3 : --dCANON accepte les noms de fichiers en majuscules # 14/05/10 : v8.4 : utilisation de jhead au lieu de exiftool # 28/05/10 : v9 : amélioration traitement --dCANON et --dHP # 08/08/10 : v10 : addComment : accepte comme arguments "begin, end, comment" # 17/10/10 : v11 : ajout option --min (extension en minuscules) # 05/01/11 : v11.1 : ajout option --maj (extension en majuscules) # 30/04/11 : v12 : affichage "(inchangé)" dans 'addComment' # 23/08/12 : v13 : prise en compte des photos NIKON FSCNxxxx.JPG et RSCNxxxx.JPG # (ajoute commentaire dans nom photo) et des vidéos .avi et .mov # 20/01/13 : v13.1 : déplacer /tmp/renomme.undo -> ~/.renomme.undo # 28/10/13 : v14 : compatible vidéos .mp4 ; addComment accepte les vidéos (variable MOTIF) # nombre de digits = au minimum celui donné par -i|--index # ajout options --titre et --renum # 21/12/13 : v15 : ajout option --exclude # 04/01/14 : v15.1 : clean utilisation de ls ($optionLS revu et $CHRONO ajouté) # ajout option --exclude-motif # 12/01/14 : v15.2 : --exclude-motif amélioré et traité comme --exclude # 18/11/15 : v16 : ajout option --apercu (aperçus .jpg/thm des vidéos .mov/avi : le nom reste le même) # 16/05/16 : v17 : compatible images .jpeg (en plus .jpg) ; addTMP aussi avec --undo (fonction cleanTMP) # 15/08/17 : v18 : ajout option -dir (si photos de plusieurs dossiers, renomme les fichiers dans leur dossier) # ajout option --include-motif (remplace option 'nomFichiers' uniquement possible avec --date) # uniformisation traitement --date avec tri alphabétique|chronologique # ajout détection de la date des vidéos avec exiftool (option --date) # 24/09/24 : v19 : ajout option --AddComment|-A # 1) Obtenir les metadata d'une PHOTO avec ImageMagick : # identify -format %[EXIF:*] photo.jpg # Toutes # identify -format %[EXIF:DateTimeOriginal] photo.jpg # Juste la date de prise de vue # # 2) Obtenir les metadata d'une PHOTO avec exiftool : # exiftool -"DateTimeOriginal" -s -s -s photo.jpg # # 3) Obtenir les metadata d'une PHOTO avec jhead : # jhead photo.jpg | grep Date/Time | grep [0-9].* -o # ou jhead photo.jpg | grep Date/Time | awk '{ print $3 " " $4}' # ou jhead photo.jpg | grep Date/Time | cut -d' ' -f6- # ou jhead photo.jpg | awk '$1=="Date/Time" {print $3 " " $4 }' #plus rapide # 4) Obtenir les metadata d'une VIDÉO avec exiftool : # exiftool -"CreateDate" -s -s -s video.mp4|mov (DateTimeOriginal fonctionne aussi parfois suivant les marques) # exiftool -"DateTimeOriginal" -s -s -s video.avi usage() { echo -e "\033[1;4mUsage\033[0m : $(basename $0) [-d|--date|-c|--chronologique]\n\t\t[-n|--nospace] [-i|--index ] [--min|--maj]\n\t\t[--titre] [--comment] [-r|--renum] [--diapo] [--dHP] [--dCANON]\n\t\t[-e|--exclude ] [-em|--exclude-motif ]\n\t\t[-im|--include-motif ] [-dir]\n\t\t[--apercu] [-y|--noconfirm] [] []" echo -e " $(basename $0) -d|--date [--check] [--affiche] [--ajoutDate]" echo " $(basename $0) [-dir] -a|-A|--{a|A}ddComment [ [] [commentaire]]" echo " $(basename $0) [-dir] -s|--supComment [ []]" echo " $(basename $0) --undo" echo echo -e " \033[1mCritères de renommage :\033[0m" echo -e " \033[34m-d|--date\033[0m (photos) ==> tri en fonction de la date contenue dans les\n\t\t\t\t données EXIF" echo -e " \033[34m-c|--chronologique\033[0m ==> tri chronologique (date du fichier)" echo " par défaut ==> tri alphabétique" echo echo -e " \033[1mOptions générales de renommage :\033[0m" echo -e " \033[34m-n|--nospace\033[0m : n'ajoute pas d'espace dans le nom des fichiers" echo -e " \033[34m-i|--index\033[0m : index à partir duquel les fichiers sont numérotés\n\t\t(1 par défaut) ; les 0 en tête sont préservés (ex. : 001)" echo -e " \033[34m--min / --maj\033[0m : met l'extension du fichier en minuscules/majuscules" echo -e " \033[34m--titre\033[0m : conserve le nom du fichier (ex. : \033[3mphoto\033[0m 45 comment.jpg)" echo -e " \033[34m--comment\033[0m : conserve les éventuels commentaires dans le nom du\n\t\tfichier (ex. : photo 45 \033[3mcomment\033[0m.jpg)" echo -e " \033[34m-r|--renum\033[0m : équivalent de --titre --comment" echo -e " \033[34m--diapo\033[0m : tient compte d'une numérotation diaporama dans le nom du\n\t\tfichier (ex. : photo \033[3m45_4\033[0m.jpg)" echo -e " \033[34m--dHP / --dCANON\033[0m : tient compte des fichiers diaporama HP / CANON\n\t\t(fichiers : hrxx0123.jpg / sta_0123.jpg)" echo -e " \033[34m--apercu\033[0m : tient compte des aperçus .jpg/thm des vidéos .mov/avi" echo -e " \033[34m-y|--noconfirm\033[0m : ne demande pas de confirmation avant le renommage" echo echo -e " \033[1mOptions pour la sélection des fichiers :\033[0m" echo -e " \033[34m-e|--exclude\033[0m : fichier à exclure du renommage" echo -e " \033[34m-em|--exclude-motif\033[0m : motif de fichier à exclure du renommage (ex. :\n\t\tsi motif='test', tous les fichiers contenant 'test' sont exclus)" echo -e " \033[34m-im|--include-motif\033[0m : motif de fichier à inclure dans le renommage\n\t\t (ne prend en compte que les fichiers contenant'motif')" echo -e " \033[34m-dir\033[0m : inclut les fichiers des dossiers contenus dans le dossier\n\t\tcourant (et les renomme dans leur propre dossier)" echo -e " \033[34mdossier\033[0m : renomme les fichiers du dossier" echo " Si non donné, dossier courant par défaut" echo -e " \033[34mnomFichiers\033[0m : liste des fichiers à renommer (ex. : $(basename $0) *.txt)" echo -e " Si non donné, renomme toutes les photos jpg et les vidéos\n\t\t\tmpg, avi, mov, mp4" echo echo -e " \033[1mOptions particulières du tri par date (-d|--date) :\033[0m" echo -e " \033[34m--check\033[0m : ne fait que tester si les photos sont bien triées" echo -e " \033[34m--affiche\033[0m : affiche la date des photos" echo -e " \033[34m--ajoutDate\033[0m : ajoute la date de la photo dans son nom sous la forme\n\t\t\"photo 45 (jj-mm-aaaa).jpg\"" echo echo -e " \033[1mAutres : gestion des commentaires et annulation :\033[0m" echo -e " \033[34m-a|--addComment\033[0m : ajoute un commentaire (en remplacement d'un autre)" echo -e " \033[34m-A|--AddComment\033[0m : ajoute un commentaire (en plus d'un autre)" echo -e " \033[34m-s|--supComment\033[0m : supprime un commentaire" echo -e " (option \033[34m--total\033[0m pour recherche approfondie)" echo -e " \033[34m--undo\033[0m : annule la dernière opération de renommage" if [ -n "$1" ]; then echo -e "\n\033[1;31m$1\033[0m\n" exit 1 fi exit } MOTIF_1="*.[jJmM][pP][gG] *.[jJmM][pP][eE][gG] *.[aA][vV][iI] *.[mM][oO][vV] *.[mM][pP]4" #liste des fichiers photos reconnus MOTIF_DIR="$MOTIF_1 */*.[jJmM][pP][gG] */*.[jJmM][pP][eE][gG] */*.[aA][vV][iI] */*.[mM][oO][vV] */*.[mM][pP]4" MOTIF=$MOTIF_1 FIRST=1 #1 tant que aucun "move" n'a été fait ; 0 sinon move() { [ $FIRST -eq 1 ] && FIRST=0 && rm $UNDO 2>/dev/null mv -i "$1" "$2$3" #-i ==> prévient si overwrite un fichier echo "$1" >> $UNDO echo "$2" >> $UNDO } addTMP="TMPTMP" #pour ne pas donner le nom d'une photo qui existerait déjà #$1 = "undo" si undo -> supprimer ".$addTMP" du 1e fichier du fichier $UNDO (et impairs) #$1 = vide sinon -> supprimer ".$addTMP" du 2e fichier du fichier $UNDO (et pairs) cleanTMP() { [ $FIRST -eq 1 ] && [ ! "$1" = "undo" ] && return #cas où aucune photo renommée echo -en "Finalisation du renommage... " [ ! "$1" = "undo" ] && PASS=1 || PASS=0 IFS=$'\n' for file in $(more $UNDO); do [ $PASS -eq 1 ] && PASS=0 && continue || PASS=1 [ -f "$file" ] && echo "Conflit de nommage : le fichier '$file' existe déjà." mv -i "$file.$addTMP" "$file" 2>/dev/null #au cas où un fichier n'a pas été copié, pas d'erreur ici done echo -en "\r\033[K" } ############# FONCTION addComment ############# RAPIDE=1 #RAPIDE=0 => test sur tous les fichiers #RAPIDE=1 => test sur les photos à partir de $begin -> $end #attributs possibles : #--total recherche rapide ou pas (cfr ci-dessus) #-s supprime le commentaire #(rien) ajoute un commentaire (en remplacement d'un éventuel) #-a ajoute un commentaire (en plus d'un éventuel) addComment() { [ "$1" = "-s" ] && DELETE=1 && shift [ "$1" = "-a" ] && ADD=1 && shift [ "$1" = "--total" ] && RAPIDE=0 && shift #1er paramètre = begin #[2è paramètre = end] <= recopie de begin si non donné #3è paramètre = comment if [ -n "$2" -a -n "$(echo $2 | sed s/[0-9]*//)" ] || [ -n "$1" -a -z "$2" ] ; then set $1 "$@" fi [ -z "$1" ] && read -p "Nombre de départ : " begin || begin="$1" [ -n "$(echo $begin | sed s/[0-9]*//)" -o -z "$begin" ] && echo "Nombre de départ non valide !" && exit 1 [ -z "$2" ] && read -p "Nombre de fin : " end || end="$2" [ -n "$(echo $end | sed s/[0-9]*//)" ] && echo "Nombre de fin non valide !" && exit 1 [ -z "$end" ] && end=$begin && echo -e "\033[1ANombre de fin : $end" [ "$begin" -gt "$end" ] && echo "Erreur : mauvaises entrées !" && exit 1 if [ "$DELETE" = 1 ]; then espaceComment="" else espaceComment=" " [ -n "$3" ] && shift && shift && comment="$*" || read -p "Commentaire : " comment [ -z "$comment" ] && echo "Erreur : commentaire vide !" && exit 1 fi echo #supprime les 0 au début du chiffre (sinon "parfois" considéré comme octal : ex. dans ${..[$num]}, for ((n=$begin;n<$(($end+1));++n)) ) begin=$(echo $begin|sed "s/^0*\(.\)/\1/") end=$( echo $end |sed "s/^0*\(.\)/\1/") [ "$KEEP_DIR" = 1 ] && optionLS="-tr $optionLS" #par défaut, tri alphabétique, sauf si KEEP_DIR=1 où ça n'a pas de sens liste="$(ls $optionLS $MOTIF 2>/dev/null)" [ -z "$liste" ] && echo "Pas de photo trouvée dans le répertoire courant !" && exit 1 [ "$RAPIDE" = 1 ] && nBegin=$(ls $optionLS $MOTIF 2>/dev/null|grep " 0*$begin\(_[0-9]\+\)\?[ \.]" -n -m1|cut -d':' -f1) #n° du fichier $begin parmi toutes les photos [ -z "$nBegin" ] && nBegin=0 for i in 1 2 ; do n=0 #pour recherche rapide num="" IFS=$'\n' #pour les noms de fichier avec espace for file in $liste; do [ ! -f "$file" ] && continue #ex. : file=*.[aA][vV][iI] si pas de fichier avi ou les dossiers (nommés xx.jpg) n=$(($n+1)) [ "$RAPIDE" = 1 ] && [ $n -lt $nBegin ] && continue [ "$RAPIDE" = 1 ] && [ -n "$num" ] && [ $num -gt $end ] && break ext=${file##*.} #1) recherche de la photo sans comment #OU num=$(expr "$file" : ".* \([0-9]\+\)\.jpg|.* \([0-9]\+\)_[0-9]\+\?\.jpg") #renvoie ce qui matche dans () ; vide sinon num=$(expr "$file" : ".* 0*\([0-9]\+\)\\(_[0-9]\+\\)\?\.$ext") #renvoie ce qui matche dans () ; vide sinon if [ -n "$num" ]; then if [ $begin -le $num ] && [ $num -le $end ]; then Tnocomment[$num]=$((${Tnocomment[$num]}+1)) if [ ! "$DELETE" = 1 ]; then nom=${file%.*} #retirer l'extension if [ $i -eq 1 ] ; then echo -e "$file\t ==> $nom \033[32m$comment\033[0m.$ext" else move "$file" "$nom $comment.$ext" fi fi fi else #2) sinon : recherche de la photo avec comment num=$(expr "$file" : ".* 0*\([0-9]\+\)\\(_[0-9]\+\\)\? .\+\.$ext") #renvoie ce qui matche dans () ; vide sinon if [ -n "$num" ]; then if [ $begin -le $num ] && [ $num -le $end ]; then Twithcomment[$num]=$((${Twithcomment[$num]}+1)) nom=$(expr "$file" : "\(.* [0-9]\+\|.* [0-9]\+_[0-9]\+\) ") #nom fichier sans comment if [ -z "$nom" ] ; then read -p "Erreur interne - fichier '$file' : commentaire pas trouvé. " else if [ $i -eq 1 ] ; then if [ ! "$file" = "$nom$espaceComment$comment.$ext" ] || [ "$ADD" = 1 ] ; then oldComment=$(expr substr "$file" $(expr length "$nom"+2) $(expr length "$file")) oldComment=${oldComment%.*} #supprime le suffixe if [ "$ADD" = 1 ]; then echo -e "$nom \033[31m$oldComment\033[0m.$ext\t==> $nom$espaceComment\033[32m$oldComment $comment\033[0m.$ext" else echo -e "$nom \033[31m$oldComment\033[0m.$ext\t==> $nom$espaceComment\033[32m$comment\033[0m.$ext" fi else echo -e "\033[37m$file\t==> (inchangé)\033[0m" fi else if [ ! "$file" = "$nom$espaceComment$comment.$ext" ] || [ "$ADD" = 1 ] ; then if [ "$ADD" = 1 ]; then oldComment=$(expr substr "$file" $(expr length "$nom"+2) $(expr length "$file")) oldComment=${oldComment%.*} #supprime le suffixe move "$file" "$nom$espaceComment$oldComment $comment.$ext" else move "$file" "$nom$espaceComment$comment.$ext" fi fi fi fi fi fi fi done if [ $i -eq 1 ] ; then nocomment=0 withcomment=0 [ ! "$DELETE" = 1 ] && for i in ${Tnocomment[@]}; do nocomment=$(($nocomment+$i)); done for i in ${Twithcomment[@]}; do withcomment=$(($withcomment+$i)); done [ "$DELETE" = 1 -a $withcomment -eq 0 ] && echo "Pas de photos avec commentaire trouvées entre $begin et $end !" && exit [ $nocomment -eq 0 -a $withcomment -eq 0 ] && echo "Pas de photos trouvées entre $begin et $end !" && exit echo -en "\033[31m" for ((n=$begin;n<$(($end+1));++n)); do l=$((${Tnocomment[$n]}+${Twithcomment[$n]}+0)) if [ $l -eq 0 ]; then [ -z "$beg" ] && echo -en "\nAttention :\t" || echo -en "\n\t\t" beg=1 echo -en "aucune photo ne porte le numéro \033[1m$n\033[0;31m" elif [ $l -ne 1 ]; then [ -z "$beg" ] && echo -en "\nAttention :\t" || echo -en "\n\t\t" beg=1 echo -en "$l photos portent le numéro \033[1m$n\033[0;31m" fi done echo -en "\033[0m" [ $nocomment -ne 0 ] && echo -en "\n > $nocomment commentaires à ajouter." [ $withcomment -ne 0 ] && echo -en "\n > $withcomment commentaires à modifier." read -p " Vous confirmez [O/n] ? " res if [ "$res" == "n" ] || [ "$res" == 'N' ]; then break fi fi done } ############# FONCTION undo ############# UNDO=~/.renomme.undo undo() { [ ! -f $UNDO ] && echo "Pas de undo possible." && exit fichTest=$(tail $UNDO -n 1) [ ! -f "$fichTest" ] && echo "Undo impossible : le fichier '$fichTest' n'existe pas." && exit N=$(wc -l $UNDO | cut -f1 -d' ') for ((n=$(($N/2));n>0;--n)); do ligne_old=$(($n*2-1)) ligne_new=$(($n*2)) old_name=$(head -$ligne_old $UNDO|tail -1) new_name=$(head -$ligne_new $UNDO|tail -1) echo -e "$new_name\t==>\t$old_name" mv -i "$new_name" "$old_name.$addTMP" done cleanTMP "undo" rm $UNDO exit } ############# TRAITEMENT DES OPTIONS ############# #valeurs par défaut : optionLS="-d --" # -d => ls ne liste pas le contenu des dossiers # -- => fin des options espace=" " espaceComment=" " index=1 PREVIEW=1 CASE_EXT="" while [ -n "$1" ]; do case "$1" in --chronologique|-c) CHRONO=1 optionLS="-tr $optionLS";; #ls -tr : tri par date (-t) croissant(-r) --date|-d) DATE=1;; --nospace|-n) espace="" espaceComment="_";; --index|-i) index=$2 [ -n "$(echo $index | sed s/[0-9]*//)" -o -z "$index" ] && usage "L'option \"$1\" doit être suivie d'un entier." shift;; --min|--maj) if [ -z "$CASE_EXT" ]; then [ "$1" = "--min" ] && CASE_EXT="min" || CASE_EXT="maj" else usage "Les options --min et --maj sont incompatibles entre elles !" fi;; --titre) KEEP_TITRE=1;; --comment) KEEP_COMMENT=1;; --renum|-r) KEEP_COMMENT=1 KEEP_TITRE=1;; --exclude|-e) [ -z "$2" ] && usage "L'option \"$1\" doit être suivie d'un fichier à exclure." excl=("${excl[@]}" "$2") shift;; --exclude-motif|-em) [ -z "$2" ] && usage "L'option \"$1\" doit être suivie d'un motif à exclure." excl=("${excl[@]}" ".*$2.*") shift;; --include-motif|-im) [ -z "$2" ] && usage "L'option \"$1\" doit être suivie d'un motif à inclure." incl=("${incl[@]}" ".*$2.*") shift;; --diapo) DIAPO=1;; --dHP) DHP=1;; --dCANON) DCANON=1;; --apercu) APERCU=1;; -dir) MOTIF=$MOTIF_DIR KEEP_DIR=1;; --noconfirm|-y) PREVIEW="";; --check) CHECK=1;; --affiche) AFFICHE=1;; --ajoutDate) AJOUTDATE=1;; --total) RAPIDE=0;; --addComment|-a) shift && addComment "$@" exit;; --AddComment|-A) shift && addComment -a "$@" exit;; --supComment|-s) shift && addComment -s "$@" exit;; --undo) undo;; --help|-h) usage;; *) #fin des options : éventuellement dossier donné puis liste de fichiers if [ -d "$1" ]; then echo "Changement de dossier : $1" cd "$1" shift fi break;; esac shift done if [ "$DATE" = "1" ] && [ "$CHRONO" = "1" ] ; then usage "L'option --date|-d n'est pas compatible avec l'option --chronologique|-c !" fi if [ "$CHECK" = "1" -o "$AFFICHE" = "1" -o "$AJOUTDATE" = "1" ] && [ "$DATE" != "1" ] ; then usage "Les options --check, --affiche et --ajoutDate ne sont valables qu'avec l'option --date|-d !" fi if [ "$KEEP_DIR" = "1" ] && [ -n "$1" ] ; then usage "L'option -dir n'est valable que sans renseigner de fichiers !" fi if [ "$RAPIDE" = "0" ] ; then usage "L'option --rapide n'est valable qu'avec les options --addComment|-a et --supComment|-s !" fi ############# FONCTIONS POUR TRIER LES PHOTOS PAR DATE ############# quit() { rm $fichDate $fichSort $fichDif 2>/dev/null exit 0 } # écrit la date des fichiers concernés dans un fichier readDate() { ###################### ### LECTURE DATE ### ###################### fichDate=/tmp/date.renomme.tmp #date des photos + nom fichier fichSort=/tmp/dateSort.tmp #idem, trié fichDif=/tmp/dateDif.tmp #différences entre fichiers fichDate/Sort rm $fichDate 2>/dev/null ; touch $fichDate #au cas où... nErr=0 #+1 à chaque photo dont on ne trouve pas de date valide nombre=$(echo "$liste" | wc -l) # ! vaut 1 aussi si la liste est vide n=0 #pour l'affichage # test de la présence de jhead JHEAD=1 which jhead >/dev/null 2>&1 if [ $? -eq 1 ]; then echo -en "\033[1m 'jhead' n'est pas installé sur votre système. Installez-le si vous voulez\n améliorer la vitesse de détection de la date.\n\n\033[0m" JHEAD=0 fi IFS=$'\n' for file in $liste; do [ ! -f "$file" ] && continue #p.ex. si dossier 'xxx.jpg' n=$(($n+1)) echo -en "[$n/$nombre] détection de la date de '$file'... " ext=`echo ${file##*.} | tr A-Z a-z` #extension du fichier en minuscules if [ "$ext" = "jpg" -o "$ext" = "jpeg" ]; then # if [["$ext" == jp[e]g ]] -> TRÈS lent if [ $JHEAD -eq 0 ]; then date="$(exiftool -"DateTimeOriginal" -s -s -s "$file")" else date="$(jhead "$file" | awk '$1=="Date/Time" {print $3 " " $4 }')" # plus rapide fi else #vidéo date="$(exiftool -"DateTimeOriginal" -s -s -s "$file")" [ $? -eq 0 ] && [ -z "$date" ] && date="$(exiftool -"CreateDate" -s -s -s "$file")" fi echo -en "\r\033[K" #retour en début de ligne + efface la ligne if [ -z "$date" ] ; then #-z : vide echo "Pas trouvé la date de '$file'" nErr=$(($nErr+1)) elif [ $(expr length "$date") -ne 19 ] ; then echo "Format de la date de '$file' non valide" nErr=$(($nErr+1)) else echo "$date>>>>$file" >> $fichDate if [ "$AFFICHE" == 1 ] ; then echo "$date [$n/$nombre] $file" fi fi done nombre=$(grep "" $fichDate -c) if [ $nombre -eq 0 ] ; then echo "Plus de photos valides !" quit fi if [ $nErr -gt 0 ] ; then echo echo -e "\033[31mAttention, $nErr/$(($nErr+$nombre)) photos non prises en compte !\033[0m" fi } #vérif si pas de fichier diaporama verifDiapo() { #photos diaporama d'appareil photos HP : type 'hrxx0123.jpg' if [ -z "$DHP" ] && [ -n "$(echo "$liste" | grep "hr..[0-9]\{4\}\.jpg$" -i)" ]; then echo -en "Il semble qu'il y ait des photos de diaporama d'appareil HP (genre\n'hrxx0123.jpg') à renommer. Voulez-vous activez l'option '--dHP' [O/n] ? " read res if [ ! "$res" == "n" ] && [ ! "$res" == 'N' ]; then DHP=1 fi echo fi #photos diaporama d'appareil photos CANON : type 'st[abc..]_0123.jpg' if [ -z "$DCANON" ] && [ -n "$(echo "$liste" | grep "st[a-z]_[0-9]\{4\}\.jpg$" -i)" ]; then echo -en "Il semble qu'il y ait des photos de diaporama d'appareil CANON (genre\n'sta_0123.jpg') à renommer. Voulez-vous activez l'option '--dCANON' [O/n] ? " read res if [ ! "$res" == "n" ] && [ ! "$res" == 'N' ]; then DCANON=1 fi echo fi #photos diaporama déjà traitées : type 'photo 45_2.jpg' if [ -z "$DIAPO" ] && [ -n "$(echo "$liste" | grep ".* [0-9]\+_[0-9]\+[ \.]")" ]; then echo -en "Il semble qu'il y ait des photos de diaporama (genre 'photo 45\033[1;7m_2\033[0m.jpg') à\nrenommer. Voulez-vous activez l'option '--diapo' [O/n] ? " read res if [ ! "$res" == "n" ] && [ ! "$res" == 'N' ]; then DIAPO=1 fi echo fi } #vérif si pas de photos NIKON de la forme FSCNxxxx.JPG et RSCNxxxx.JPG (=photos retouchées sur l'appareil) verifNIKON() { #vérification de la présence de photos NIKON #rappel : $liste peut contenir la date des photos ainsi qu'un dossier (càd pas ajouter '^' à "grep "^...JPG$") if [ -n "$(echo "$liste" | grep "[FR]SCN[0-9]\{4\}\.JPG$" -i)" ]; then echo -en "Il semble qu'il y ait des photos retouchées avec un appareil NIKON (genre\n'\033[1;7mF\033[0mSCN0123.JPG' ou '\033[1;7mR\033[0mSCN0123.JPG') à renommer. Voulez-vous en tenir compte ?\nCela rajoutera un commentaire dans le nom de la photo [O/n] ? " read res if [ ! "$res" == "n" ] && [ ! "$res" == 'N' ]; then NIKON_FR=1 fi if [ ! "$CHRONO" = "1" ] && [ ! "$DATE" = "1" ]; then echo -en "Attention, vous avez choisi un tri alphabétique. Ces photos ne seront pas triées\npar date. Voulez-vous opter pour un tri chronologique [O/n] ? " read res if [ ! "$res" == "n" ] && [ ! "$res" == 'N' ]; then CHRONO=1 optionLS="-tr $optionLS" fi fi echo fi } #vérif si pas d'aperçu vidéo verifApercu_modifListe() { #fichier .thm (aperçu d'une video .avi Canon) motifTHM="*.[tT][hH][mM]" [ "$KEEP_DIR" = 1 ] && motifTHM="$motifTHM */*.[tT][hH][mM]" if [ -z "$APERCU" ] && ( ( [ $type = "photos" ] && [ -n "$(ls $motifTHM 2>/dev/null)" ] ) || [ -n "$(echo "$liste" | grep "\.thm$" -i)" ] ); then echo -en "Il y a des aperçus vidéos (fichiers .thm) à renommer. Voulez-vous activez\nl'option '--apercu' [O/n] ? " read res if [ ! "$res" == "n" ] && [ ! "$res" == 'N' ]; then APERCU=1 fi echo fi #fichier .jpg (aperçu d'une video .mov de même nom) if [ -z "$APERCU" ] && [ -n "$(echo "$liste" | tr movMOV jpgJPG | uniq -d)" ]; then echo -en "Il semble qu'il y ait des aperçus vidéos (fichiers .jpg et .mov de même nom) à\nrenommer. Voulez-vous activez l'option '--apercu' [O/n] ? " read res if [ ! "$res" == "n" ] && [ ! "$res" == 'N' ]; then APERCU=1 fi echo fi #modifier la liste des fichiers : suppression des aperçus de la liste (pour qu'ils gardent le même nom que la vidéo) if [ "$APERCU" = "1" ] ; then # Vidéo (mov) et aperçu (jpg) portant le même nom IFS=$'\n' for f in $(echo "$liste"|grep \.[mM][oO][vV]$) ; do extApercu=`echo ${f##*.} | tr movMOV jpgJPG` jpg="$(echo "${f%.*}\.$extApercu"|sed "s#/#\\\/#")" #rem : sed "/.../d" -> marche pas si $f contient '/' liste="$(echo "$liste"|sed "/^$jpg$/d")" done # Vidéo (avi) et aperçu (thm) -> supprimer fichiers thm [rem : pas nécessaire si type="photos" car .thm pas dans liste] liste="$(echo "$liste"|sed "/^.*\.[tT][hH][mM]$/d")" nombre=$(echo "$liste" | wc -l) # ! vaut 1 aussi si la liste est vide fi } ############# TYPE ET NOMBRE DE FICHIERS ############# if [ $# -eq 0 ] ; then #Photos uniquement type="photos" #par défaut : photos et vidéos liste="$(ls $optionLS $MOTIF 2>/dev/null)" else type="fichiers" liste="$(ls $optionLS "$@" 2>/dev/null)" #Vérif si tous les fichiers existent for file in "$@" ; do if [ ! -f "$file" ] && [ ! -d "$file" ] ; then echo -e "Ce fichier n'existe pas : \033[31m$file\033[0m" elif [ -d "$file" ] ; then liste="$(echo "$liste"|sed "/^$file$/d")" #suppression des dossiers de la liste fi done fi # Exclusion des fichiers for f in "${excl[@]}" ; do liste="$(echo "$liste"|sed "/^$f$/d")" done # Inclusion des fichiers for f in "${incl[@]}" ; do liste="$(echo "$liste"|sed "/^$f$/!d")" done [ -z "$liste" ] && echo "Aucun fichier trouvé." && exit if [ "$DATE" = "1" ]; then #tri de photos par date readDate ############# ### TRI ### ############# sort $fichDate > $fichSort diff $fichDate $fichSort > $fichDif #diff renvoie 0 si les mêmes fichiers, 1 si qq différences ou 2 sinon if [ $? -eq 0 ] ; then echo -e "\033[32mLes $nombre photos sont bien triées par date.\033[0m" [ "$CHECK" == 1 ] && quit read -p "Voulez-vous quand même les renommer [o/N] ? " res if [ ! "$res" == "o" ] && [ ! "$res" == 'O' ]; then quit fi else echo -e "\033[31mLes $nombre photos ne sont pas triées par date ($(grep -c "^> " $fichDif) différences).\033[0m" [ "$CHECK" == 1 ] && quit fi #fichSort contient la liste des fichiers triés par date #si AJOUTDATE => contient aussi la date [ "$AJOUTDATE" != "1" ] && sed -i "s/.*>>>>//" $fichSort type="photos" liste="$(more $fichSort)" verifApercu_modifListe verifDiapo verifNIKON else verifApercu_modifListe #peut modifier nombre de fichiers # Nombre de fichiers nombre=$(echo "$liste" | wc -l) # ! vaut 1 aussi si la liste est vide [ -z "$liste" ] && echo "Aucun fichier trouvé." && exit #photos NIKON. Si tri par ordre alphabétique, éventuellement retrier par ordre chronologique orig_CHRONO=$CHRONO verifNIKON if [ "$CHRONO" = "1" ] && [ ! "$orig_CHRONO" = "$CHRONO" ] ; then # avec IFS=$'\n' -> ne pas mettre d'espace en trop dans les options de ls liste=$(optionLSlist=($optionLS) ; IFS=$'\n' ; ls ${optionLSlist[@]} $liste) fi #diaporama HP / CANON. Si tri par ordre alphabétique, mettre les fichiers de diaporama au bon endroit verifDiapo if [ ! "$CHRONO" = "1" ] ; then if [ "$DHP" = "1" ] && [ "$DCANON" = "1" ]; then liste="$(echo "$liste"|sed "s/^\(.*\/\)\?\([sS][tT][a-zA-Z]_\([0-9]\{4\}\)\.[jJ][pP][gG]\)$/\1img_\3.jpg\t\2/" \ |sed "s/^\(.*\/\)\?\([hH][rR][a-zA-Z0-9]\{2\}\([0-9]\{4\}\)\.[jJ][pP][gG]\)$/\1hpim\3.jpg\t\2/" \ |sort \ |sed "s/^\(.*\/\)\?hpim[0-9]\{4\}.jpg\t\([hH][rR][a-zA-Z0-9]\{2\}[0-9]\{4\}\.[jJ][pP][gG]\)$/\1\2/" \ |sed "s/^\(.*\/\)\?img_[0-9]\{4\}.jpg\t\([sS][tT][a-zA-Z]_[0-9]\{4\}\.[jJ][pP][gG]\)$/\1\2/")" elif [ "$DHP" = "1" ]; then liste="$(echo "$liste"|sed "s/^\(.*\/\)\?\([hH][rR][a-zA-Z0-9]\{2\}\([0-9]\{4\}\)\.[jJ][pP][gG]\)$/\1hpim\3.jpg\t\2/" \ |sort \ |sed "s/^\(.*\/\)\?hpim[0-9]\{4\}.jpg\t\([hH][rR][a-zA-Z0-9]\{2\}[0-9]\{4\}\.[jJ][pP][gG]\)$/\1\2/")" elif [ "$DCANON" = "1" ]; then liste="$(echo "$liste"|sed "s/^\(.*\/\)\?\([sS][tT][a-zA-Z]_\([0-9]\{4\}\)\.[jJ][pP][gG]\)$/\1img_\3.jpg\t\2/" \ |sort \ |sed "s/^\(.*\/\)\?img_[0-9]\{4\}.jpg\t\([sS][tT][a-zA-Z]_[0-9]\{4\}\.[jJ][pP][gG]\)$/\1\2/")" fi fi echo -en "\033[1m$nombre $type\033[0m à renommer suivant \033[1m" [ "$CHRONO" = "1" ] && echo -en "la date des fichiers" || echo -en "l'ordre alphabétique" echo -e "\033[0m." fi # Nom (titre) des fichiers : if [ "$KEEP_TITRE" != "1" ]; then titre=$(echo "$liste" | head -1 | sed "s/.*>>>>//") #1ère ligne titre=${titre%% [0-9]*} #supprime le plus grand suffixe read -p "> Nom des $type ['$titre' par défaut ] : " res [ "$res" != "" ] && titre=$res [ "$KEEP_DIR" = 1 ] && titreFile=$titre #mémorisation du titre fi #en cas de photos, par défaut mettre l'extension en minuscules [ $type = "photos" ] && [ -z "$CASE_EXT" ] && CASE_EXT="min" n_digit=$(expr length $((nombre+10#$index-1))) #nombre de digits (dans nom fichier) [ $(expr length $index) -gt $n_digit ] && n_digit=$(expr length $index) #nombre de digits = au minimum celui donné par -i|--index index=$(echo $((10#$index))) #conversion en décimal n_digitAffich=$(expr length $nombre) #nombre de digits (pour affichage) ############# RENOMMAGE ############# for i in 1 2 ; do n=$((index-1)) #n° fichier nAffich=0 #n° pour affichage uniquement IFS=$'\n' for file in $liste do if [ "$AJOUTDATE" == "1" ]; then date=$(echo "$file"|sed "s/\([0-9]*\):\([0-9]*\):\([0-9]*\).*/\3-\2-\1/") addDate="$espaceComment($date)" file=$(echo "$file"|sed "s/.*>>>>//") fi if [ ! -f "$file" ] ; then if [ -d "$file" ] ; then echo -e "\033[1m'$file' est un dossier\033[0m" else echo -e "\033[31mErreur interne - ce fichier n'existe pas : $file\033[0m" fi continue fi #extension ext=${file##*.} if [ "$ext" = "$file" ] ; then #pas d'extension ext="" else ext=".$ext" fi if [ "$CASE_EXT" = "min" ] ; then ext=`echo $ext | tr A-Z a-z` #extension du fichier en minuscules elif [ "$CASE_EXT" = "maj" ] ; then ext=`echo $ext | tr a-z A-Z` #extension du fichier en majuscules fi #aperçu vidéo if [ "$APERCU" = "1" ] ; then fileApercu="" if [[ "$ext" == \.[mM][oO][vV] ]] ; then extApercu=`echo ${file##*.} | tr movMOV jpgJPG` if [ -e ${file%.*}.$extApercu ] ; then fileApercu=${file%.*}.$extApercu extApercu=`echo $ext | tr movMOV jpgJPG` fi elif [[ "$ext" == \.[aA][vV][iI] ]] ; then extApercu=`echo ${file##*.} | tr aviAVI thmTHM` if [ -e ${file%.*}.$extApercu ] ; then fileApercu=${file%.*}.$extApercu extApercu=`echo $ext | tr aviAVI thmTHM` fi fi fi comFile="" #traitement du titre #conservation du nom (titre) de la photo #lorsque le nom est du type 'noël 012 Farnières.jpg' ==> 'noël' if [ "$KEEP_TITRE" = 1 ] ; then titre=${file%% [0-9]*} #supprime le plus grand suffixe [ "$titre" = "$file" ] && titre=${file%.*} #on supprime juste l'extension fi #fin traitement du titre #traitement des commentaires #conservation d'un éventuel commentaire dans le nom de la photo #lorsque le nom est du type 'noël 012 Farnières.jpg' ==> 'Farnières' #OLD : comFile=${file#* [0-9]* } #supprime le préfixe (va pas bien si chiffre avant) #OLD : if [ "$comFile" == "$file" ] ; then #y'a pas de commentaires if [ "$KEEP_COMMENT" = 1 ] ; then if [ "$DIAPO" = 1 ] ; then index_com=$(expr "$file" : ".* [0-9]\+ \|.* [0-9]\+_[0-9]\+ ") else index_com=$(expr "$file" : ".* [0-9]\+ ") #index_com=$(expr "$file" : ".* [0-9]\+ .") #rem : attention, certains caractères (ÉÈ...) comptent pour 2 fi if [ $index_com -ne 0 ] ; then comFile=$(expr substr "$file" $((index_com+1)) $(expr length "$file")) comFile=${comFile%$ext} #supprime le suffixe fi fi #fin traitement des commentaires #KEEP_DIR (titre est déjà modifié si KEEP_TITRE) if [ "$KEEP_DIR" = 1 ] && [ "$KEEP_TITRE" != "1" ]; then dir=${file%/*} [ "$dir" = "$file" ] && dir="" || dir="$dir/" titre="$dir${titreFile}" fi #fin KEEP_DIR #traitement des photos NIKON #ajout d'un éventuel commentaire if [ "$NIKON_FR" = 1 ] ; then FR=$(expr "/$file" : "^.*\/\([FfRr]\)[Ss][Cc][Nn][0-9]\{4\}\.[jJ][pP][gG]$" | tr A-Z a-z ) if [ "$FR" = "f" ] ; then comFile="(retouché par NIKON)" elif [ "$FR" = "r" ] ; then comFile="(zoom par NIKON)" fi fi #fin traitement des photos NIKON #traitement des diaporamas #ajout d'un éventuel suffixe au n° de la photo (ex. : '_05' dans 'photo 012_05 comment.jpg') ajout="" #1) diaporama CANON : fichier type 'st[abc..]_0123.jpg' if [ "$DCANON" = "1" ]; then seq=$(expr "/$file" : "^.*\/[sS][tT]\([a-zA-Z]\)_[0-9]\{4\}\.[jJ][pP][gG]$") #renvoie ce qui matche dans () ; vide sinon if [ -n "$seq" ] ; then seq=$(echo $seq|tr A-Z a-z) #en minuscule numDiap=$(( $(printf "%d" \'$seq) - $(printf "%d" \'a) + 1 )) #a=>1 ; b=>2 ; ... numDiap=$(printf %02d $numDiap) #1 => 01 ; 2 => 02 ; ... ajout="_$numDiap" if [ $numDiap -ne 1 ]; then n=$((n-1)); fi fi fi #2) diaporama HP : fichier type 'hrxx0123.jpg' if [ "$DHP" = "1" ]; then seq=$(expr "/$file" : "^.*\/[hH][rR][a-zA-Z0-9]\([a-zA-Z0-9]\)[0-9]\{4\}\.[jJ][pP][gG]$") #renvoie ce qui matche dans () ; vide sinon if [ -n "$seq" ] ; then [ -z "$oldSeq" ] && oldSeq=0 if [ "$seq" = "$oldSeq" ]; then numDiapHP=$(($numDiapHP+1)) else numDiapHP=1 fi oldSeq=$seq numDiapHP=$(printf %02d $numDiapHP) #1 => 01 ; 2 => 02 ; ... ajout="_$numDiapHP" if [ $numDiapHP -ne 1 ]; then n=$((n-1)); fi fi fi #3) diaporama déjà traitées : fichier type 'photo 45_2.jpg' if [ "$DIAPO" = 1 ] ; then numDiap=$(expr "$file" : ".* [0-9]\+_\([0-9]\+\)[ \.]") #renvoie ce qui matche dans () ; vide sinon if [ -n "$numDiap" ]; then ajout="_$numDiap" if [ $numDiap -ne 1 ]; then n=$((n-1)); fi fi fi #fin traitement des diaporamas n=$(($n+1)) nAffich=$(($nAffich+1)) n0=$(printf %.${n_digit}d $n) #$n précédé de 0 nAffich0=$(printf %.${n_digitAffich}d $nAffich) #$nAffich précédé de 0 [ -n "$comFile" ] && comFile="$espaceComment$comFile" nom="${titre}${espace}${n0}${ajout}$addDate$comFile${ext}" nomAffich="${titre}${espace}\033[1m${n0}${ajout}\033[0;32m$addDate$comFile\033[0m${ext}" echo -en "\r\033[K" if [ ! "$file" = "$nom" ] ; then echo -en "[$nAffich0/$nombre] $file\t==>\t$nomAffich " [ -n "$fileApercu" -a $i -eq 1 ] && \ echo -en "\n$(echo $nAffich0$nombre|tr 0-9 " ") $fileApercu\t==>\t${nomAffich%.*}$extApercu" if [ -z "$PREVIEW" ] || [ $i -eq 2 ]; then move "$file" "$nom" ".$addTMP" [ -n "$fileApercu" ] && move "$fileApercu" "${nom%.*}$extApercu" ".$addTMP" fi else echo -en "[$nAffich0/$nombre] \033[37m$file\t==>\t(inchangé)\033[0m" [ -n "$fileApercu" -a $i -eq 1 ] && \ echo -en "\n$(echo $nAffich0$nombre|tr 0-9 " ") \033[37m${nom%.*}$extApercu\t==>\t(inchangé)\033[0m" fi [ $i -eq 1 ] && echo done [ -z "$PREVIEW" ] && break if [ $i -eq 1 ]; then echo read -p "Vous confirmez [O/n] ? " res if [ "$res" == "n" ] || [ "$res" == 'N' ]; then quit fi else echo -en "\r\033[K" fi done cleanTMP quit