2 votes

Écriture d'un script/fichier batch pour convertir une structure entre deux dossiers/fichiers.

Je suis très mauvais avec les fichiers batch/scripts, surtout comparé à ceux qui les maîtrisent :). J'aimerais vraiment avoir de l'aide pour créer un simple (et facile à "ajuster") fichier batch/scripts qui pourrait m'aider à faire ce que j'ai besoin de faire (décrit ci-dessous).

J'essaie de convertir la structure des répertoires de mes photos. La plupart de ces répertoires sont organisés d'une manière unique ou similaire et j'aimerais les convertir en une structure différente, plus pratique pour moi.

Ma structure actuelle est la suivante -

PhotosCollection01\
|-> Img003.jpg
|-> Img004.jpg
|-> Img005.jpg
|-> Img007.jpg
|-> Img010.jpg
|-> ...
|-> Chosen\
    |-> Img005.jpg
    |-> Img010.jpg

Le fichier batch/script devrait changer la structure en ceci -

PhotosCollection01\
|-> NewName001.jpg (formerly Img003.jpg)
|-> NewName002.jpg (formerly Img004.jpg)
|-> NewName004.jpg (formerly Img007.jpg)
|-> ...
|-> Chosen\
    |-> NewName003.jpg (formerly Img005.jpg)
    |-> NewName005.jpg (formerly Img010.jpg)

C'est ce que le fichier batch/script a fait -

1) Names are all "NewName???.jpg" (from 001 and up)
2) No duplication of photos under the "Photos" directory and its sub-dirs
3) The "Chosen" directory holds the same amount of photos as before (these were removed from the "Photos" directory)
4) The numbering order of the "NewName" photos is kept in the same order as the "Img" order (although numbering is reset to start from 000)
5) I would love to be able to have "PhotosCollectionXX", "NewNameXXX" and "Chosen" to be able to consist of spaces in their real names

Jusqu'à (si) j'obtiens une réponse, je vais essayer d'apprendre et d'écrire le script moi-même. Toute aide serait très appréciée !

Merci d'avance, Eyal

1voto

Magoo Points 22274
@ECHO OFF
SETLOCAL
SET "relroot=u:\photos collection 01"
SET "oldmask=im age"
SET "newmask=new name"
SET "ext=jpg"
SET "skipped="
::
:: step 1 - ensure no 'newname*.ext' exists in the subtree
::
FOR /f %%i IN (
  'DIR /s/b/a-d "%relroot%\%newmask%*.%ext%" 2^>nul^|FIND /c /v "" '
 ) DO IF NOT %%i==0 ECHO Files matching new mask already exist&GOTO :EOF 
::
:: step 2 - list target files
::
:temploop
SET tempfile=%temp%\Photo%random%
IF EXIST "%tempfile%*" GOTO temploop
:: now have random tempfile name
(
FOR /f "delims=" %%i IN (
  'DIR /s/b/a-d "%relroot%\%oldmask%*.%ext%" '
  ) DO (
  ECHO %%~ni*%%~fi
)
)>"%tempfile%1"
::
:: Now do the rename
::
SET count=1000
SET prev=%newmask%
FOR /f %%i IN ('find /c "*" ^<"%tempfile%1"') DO IF %%i gtr 1000 ECHO %%i files - exceeds capacity&GOTO :eof
FOR /f "delims=*" %%i IN ('SORT "%tempfile%1"') DO (CALL :incren "%%i")
IF DEFINED skipped ECHO some files were NOT renamed&DIR /s/b/a-d "%relroot%\%oldmask%*.%ext%"

DEL "%tempfile%1"
GOTO :eof

:incren
:: repeat?
IF "%prev%"==%1 GOTO :EOF
:: no - process next name found
SET "prev=%~1"
FOR %%n IN (firstname secondname) DO (SET %%n=)
:: scan the tempfile, looking for matches to name found
FOR /f "usebackqtokens=1,2delims=*" %%m IN ("%tempfile%1") DO IF /i "%%m"=="%prev%" (
 IF DEFINED firstname SET skipped=Y&IF NOT DEFINED secondname SET secondname=%%n
 IF NOT DEFINED firstname SET firstname=%%n
)
IF DEFINED secondname SET firstname=%secondname%
ECHO REN "%firstname%" "%newmask%%count:~-3%.%ext%"
SET /a count+=1
GOTO :eof

Eh bien, pas trop difficile après tout.

Je ne suis pas tout à fait d'accord avec votre spécification - je ne supprime pas les fichiers, donc je n'ai simplement pas renommé les cibles avec des noms dupliqués.

On accorde beaucoup trop d'attention à essayer de traiter des noms de fichiers stupides. Si vous utilisez des caractères comme !%^)= dans vos noms de fichiers - et bien - vous êtes si intelligent - vous avez compris.

Donc, en supposant que les caractères et les espaces des noms de fichiers sont raisonnables, cela fonctionne !

Configurez d'abord votre relative root (sous-répertoire de départ), les masques de fichiers à utiliser, anciens et nouveaux, et l'extension. J'ai utilisé le set "var=string" syntaxe pour éviter l'application d'espaces terminaux parasites qui sont invisibles et peuvent provoquer le chaos. Notez également que dans une affectation de chaîne de caractères, les espaces des deux côtés de '=' sont significatifs.

La première étape est telle que documentée. Je ne suis pas sûr de ce qu'il faut faire s'il y a déjà des fichiers correspondant au nouveau nom dans l'arbre - alors je ne fais rien. Je compte les lignes qui apparaissent à partir d'un fichier dir /s/b/a-d (répertoire, avec sous-répertoires, forme de base (donc pas d'en-tête) et pas de nom de répertoire) devrait être d'environ 0 si tout va bien.

J'aime configurer les tempfiles en utilisant la méthode showm. S'il n'y a pas de noms dans %temp% correspondant au nom aléatoire choisi, alors il devrait être sûr d'utiliser ce nom + n'importe quelle annexe que vous souhaitez (afin de pouvoir créer plusieurs tempfiles, si nécessaire).

L'étape suivante consiste à récupérer le sous-répertoire des fichiers de l'ancien nom sous une forme basique, mais cette fois dans un fichier temporaire. Ce qui est sorti est une ligne pour chaque fichier, structurée comme la partie NOM seulement ( %%~ni ) un astérisque et le nom complet du fichier ( %%~fi ). L'astérisque agit comme un délimiteur de colonne et est sûr parce que * ne peut pas apparaître dans un nom de fichier.

Vient ensuite la phase de renommage. Nous commençons le COUNT à 1000 afin que nous puissions utiliser les 3 derniers caractères pour créer le nom. Si vous voulez commencer à 001, utilisez plutôt 1001. PREV est initialisé à une valeur qui ne peut pas apparaître comme un nom de fichier à renommer.

De nouveau, comptez les noms à renommer. S'il y en a trop, abandonnez le navire.

L'étape suivante consiste à trier le fichier temporaire, afin que le résultat soit traité dans l'ordre du nom du fichier de base original (avant le "*" dans chaque ligne) et ensuite, si le nom correspond, dans l'ordre alphabétique du nom du sous-répertoire (puisque nom*parent sera trié avant nom*parent). \subdir ). Chaque NOM rencontré est ensuite transmis à la fonction :incren routine - cité pour tenir compte de l'exigence des espaces dans les noms de fichier.

La première chose que fait la routine INCREN est de vérifier si le nom répète le nom précédent rencontré. Si c'est le cas, le nom est ignoré (car il a déjà été traité). PREV est alors fixé au prochain nom rencontré. SET "prev=%~1" supprime les guillemets du premier paramètre, puis attribue le résultat à prev et les guillemets empêchent les espaces parasites de s'intercaler. firstname y secondname sont alors fixés à [rien].

Ensuite, nous analysons à nouveau le fichier temporaire, en recherchant un nom correspondant comme premier jeton et en assignant le deuxième jeton (le nom complet du fichier) à la fonction %%n

lorsque le premier est trouvé, le prénom n'est pas défini, il faut donc le définir comme le nom complet du fichier. Si un second nom est trouvé, alors firstname sera déjà défini, alors définissez SKIPPED pour signaler qu'un problème a été rencontré. Si le deuxième nom de fichier n'a pas encore été défini, alors l'option secondname a que nom du fichier complet Si d'autres correspondances sont trouvées, alors comme secondname est maintenant défini, rien d'autre ne sera fait.

Après avoir traité le dossier, nous aurons firstname fixé au premier nom de fichier complet (puisque le relative-Root est le premier rencontré) et secondname ne sera défini que si 2 noms correspondants ou plus ont été trouvés. Dans ce cas, l'option firstname à la valeur du deuxième nom rencontré, qui sera dans un sous-répertoire inférieur.

Maintenant, faites le RENAME. J'ai juste ECHO mais pour l'activer, il faut retirer le ECHO de la ECHO REN... ligne. Nous savons firstname contient le nom complet du fichier à renommer, et nous savons que la structure du nouveau nom de fichier sera le nouveau masque + les 3 derniers caractères de COUNT +un point+l'extension sélectionnée.

et remettre le compte à zéro pour le prochain renommage...

Voici un essai avec le ECHO retiré :

============= before =========

u:\photos collection 01\im age 612.jpg
u:\photos collection 01\im age 003.jpg
u:\photos collection 01\im age 005.jpg
u:\photos collection 01\im age 610.jpg
u:\photos collection 01\im age 009.jpg
u:\photos collection 01\im age 609.jpg
u:\photos collection 01\im age 505.jpg
u:\photos collection 01\selection 01\im age 001.jpg
u:\photos collection 01\selection 01\im age 004.jpg
u:\photos collection 01\selection 01\im age 005.jpg
u:\photos collection 01\selection 01\im age 006.jpg

=============  run  =========

some files were NOT renamed
u:\photos collection 01\im age 005.jpg

============= after  =========

u:\photos collection 01\new name009.jpg
u:\photos collection 01\new name001.jpg
u:\photos collection 01\im age 005.jpg
u:\photos collection 01\new name008.jpg
u:\photos collection 01\new name005.jpg
u:\photos collection 01\new name007.jpg
u:\photos collection 01\new name006.jpg
u:\photos collection 01\selection 01\new name000.jpg
u:\photos collection 01\selection 01\new name002.jpg
u:\photos collection 01\selection 01\new name003.jpg
u:\photos collection 01\selection 01\new name004.jpg

Notez que ceci a été exécuté sur un lecteur FAT, donc la séquence des fichiers réels est la même dans les deux listings.

0voto

user2270404 Points 1882

Vous pourriez être en mesure de réaliser ceci sans scripts, si vous avez Total Commander sous Windows (d'après vos séparateurs de chemin dans l'exemple, je suppose que vous utilisez Windows). Si vous appuyez sur Ctrl+B, il liste tous les fichiers du répertoire actuel et tous les sous-répertoires dans une liste. Ensuite, si vous les sélectionnez tous (*) et que vous appuyez sur Ctrl+M, l'outil de renommage par lot apparaît et vous pouvez tous les renommer, définir le remplacement de Img par NewName et ajouter un compteur à la fin du nom du fichier.

0voto

Endoro Points 34982

Essayez ceci et retirez le echo avant move si la sortie est correcte :

@echo off&setlocal
set "sourcefolder=PhotosCollection01"

for /r "%sourcefolder%" %%i in (*.jpg) do (
    if defined "$n%%~nxi" set "$d%%~nxi=%%~nxi"
    set "$p%%~nxi=%%~dpi"
    set "$n%%~nxi=%%~nxi"
)
set "$d" >nul 2>&1 && (
    echo(Duplicate filename(s^):
    for /f "tokens=2delims==" %%i in ('set $d') do echo(%%i
    goto:eof
)
set /a counter=1000
for /f "tokens=2delims==" %%i in ('set $n') do (
    set /a counter+=1
    setlocal enabledelayedexpansion
    if exist "!$p%%~i!NewName!counter:~-3!%%~xi" (
    echo(file already exists: "!$p%%~i!NewName!counter:~-3!%%~xi"
    ) else echo move "!$p%%~i!%%~i" "!$p%%~i!NewName!counter:~-3!%%~xi"
    endlocal
)

Le script se termine, si des noms de fichiers en double sont trouvés dans les sous-dossiers. Si le fichier cible existe déjà, il ne sera pas écrasé. Veuillez noter que tous les dossiers de %sourcefolder% utilisent le même compteur. Si vous avez différentes sélections, appelez ce script pour chacune d'elles ou écrivez un commentaire.

0voto

Aacini Points 19316

Sujet intéressant ! Je comprends votre demande de la façon suivante : 1- Créez une liste de noms de fichiers uniques à partir de PhotosCollection et Chosen, mais donnez la priorité aux fichiers de Chosen (les fichiers de PhotosCollection avec le même nom seront supprimés). 2- Renommez les fichiers de la liste avec des numéros consécutifs à partir de 001. Le fichier Batch ci-dessous réalise ce processus, mais il traite tous dans le répertoire courant (de PhotosCollection01 à PhotosCollectionNN) et traiter de cette façon tous les sous-répertoires sous chaque répertoire, c'est-à-dire que si les sous-répertoires choisis ont des "frères", ils sont tous traités de la même manière.

@echo off
setlocal

rem Set this value as you wish (ie: set NewName=New Name With Spaces)
set NewName=NewName

rem Process all directories at this level
for /D %%a in (*) do (
   rem Enter into this directory (ie: PhotosCollection01)
   cd "%%a"
   rem Insert file names in the initial list as "parent" (ie: Img003.jpg Img004.jpg Img005.jpg)
   setlocal EnableDelayedExpansion
   for %%c in (*.jpg) do (
      set unique[%%c]=.
   )
   rem Process each subdirectory
   for /D %%b in (*) do (
      rem Enter into this subdirectory (ie: Chosen)
      cd "%%b"
      rem Process "nested" file names (ie: Img005.jpg Img010.jpg)
      for %%c in (*.jpg) do (
         if "!unique[%%c]!" equ "." (
            rem Delete duplicated file in parent directory (ie: PhotosCollection01\Img005.jpg)
            del "..\%%c"
         )
         rem Insert file name in the list as "nested"
         set unique[%%c]=%%b
      )
      rem Go back to parent directory (ie: PhotosCollection01)
      cd ..
   )
   rem Rename all names in the list from 001 and up
   set number=1000
   for /F "tokens=2,3 delims=[]=" %%c in ('set unique[') do (
      set /A number+=1
      ren "%%d\%%c" "%NewName%!number:~-3!.jpg"
   )
   rem Delete the list
   endlocal
   rem Go back to original directory (where PhotosColection01...NN exist)
   cd ..
)

Placez ce fichier Batch dans le même dossier que celui qui contient les Collections et exécutez-le, vous devez le faire avec des fichiers de test plusieurs fois jusqu'à ce que vous soyez satisfait du résultat. Notez que la méthode peut être facilement modifiée afin de supprimer ou renommer les fichiers dupliqués dans tous les dossiers frères de Chosen, c'est-à-dire, si le dossier "Chosen2" contient le fichier Img010.jpg (qui est aussi dans Chosen), supprimez ou renommez celui de Chosen ou Chosen2 (actuellement ils sont conservés, mais pas renommés). Tous les noms de répertoires et de fichiers peuvent comporter des espaces, mais les noms comportant des points d'exclamation ne seront pas correctement traités ; ce détail peut être corrigé, si nécessaire.

C:\Users\Antonio\Documents\test
>dir /b
PhotosCollection01
renumber.bat

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01
Chosen
Img003.jpg
Img004.jpg
Img005.jpg
Img007.jpg
Img010.jpg

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01\Chosen
Img005.jpg
Img010.jpg

C:\Users\Antonio\Documents\test
>renumber.bat

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01
Chosen
NewName001.jpg
NewName002.jpg
NewName004.jpg

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01\Chosen
NewName003.jpg
NewName005.jpg

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X