Problème avec un fichier .bat

Résolu/Fermé
Argrat Messages postés 1 Date d'inscription mardi 7 mai 2013 Statut Membre Dernière intervention 7 mai 2013 - 7 mai 2013 à 16:19
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 - 11 mai 2013 à 23:24
Bonjour,

J'ai eu a faire une petite tâche qui consiste à supprimer des fichiers et dossiers de plus de X jours avec la gestion des mois.
Pour ce faire j'ai fait le programme suivant :

@echo off
rem --------------------------------------------
rem SUPPRESSION DES ANCIENS FICHIERS ET DOSSIERS
rem --------------------------------------------

rem la varianble mois correspond au mois precedent d'ou le moins un
set /a moisprece=%date:~3,2%-1

rem la variable dossierMois correspond au mois actuel
set moisactu=%date:~3,2%

rem la variable chemin correspond au chemin a emprunter pour acceder au dossier
set chemin=C:\Cameras\

rem la variable jours correspond à la limite de jours avant la suppression du dossier
set jours=10

if %moisprece% EQU 0 goto DECEMBRE
if %moisprece% LEQ 9 goto TRAITEMENT
if %moisprece% GEQ 10 goto MOIS1

:TRAITEMENT
set moisprece=0%moisprece%
goto MOIS1

:DECEMBRE
set moisprece=12
goto MOIS1

:MOIS1
if %moisprece% EQU 01 goto JANVIER1
if %moisprece% EQU 02 goto FEVRIER1
if %moisprece% EQU 03 goto MARS1
if %moisprece% EQU 04 goto AVRIL1
if %moisprece% EQU 05 goto MAI1
if %moisprece% EQU 06 goto JUIN1
if %moisprece% EQU 07 goto JUILLET1
if %moisprece% EQU 08 goto AOUT1
if %moisprece% EQU 09 goto SEPTEMBRE1
if %moisprece% EQU 10 goto OCTOBRE1
if %moisprece% EQU 11 goto NOVEMBRE1
if %moisprece% EQU 12 goto DECEMBRE1


:JANVIER1
set moisprece=January
set moisactu=February
goto FIN

:FEVRIER1
set moisprece=February
set moisactu=March
goto FIN

:MARS1
set moisprece=March
set moisactu=April
goto FIN

:AVRIL1
set moisprece=April
set moisactu=May
goto FIN

:MAI1
set moisprece=May
set moisactu=June
goto FIN

:JUIN1
set moisprece=June
set moisactu=July
goto FIN

:JUILLET1
set moisprece=July
set moisactu=August
goto FIN

:AOUT1
set moisprece=August
set moisactu=September
goto FIN

:SEPTEMBRE1
set moisprece=September
set moisactu=October
goto FIN

:OCTOBRE1
set moisprece=October
set moisactu=November
goto FIN

:NOVEMBRE1
set moisprece=November
set moisactu=December
goto FIN

:DECEMBRE1
set moisprece=December
set moisactu=January
goto FIN

:FIN
echo The previous mouth was %moisprece%, now we are in %moisactu%.

rem elimine les fichiers trop anciens du mois actuel
forfiles -p %chemin%%moisactu% -s -d -%jours% -m *.* -c "cmd /c del @FILE

rem elimine les dossiers trop anciens du mois actuel
forfiles /p %chemin%%moisactu% -s -d -%jours% -c "cmd /c if @isdir == TRUE RMDIR /S /Q @path"

rem elimine les fichiers trop anciens du mois precedent
forfiles /p %chemin%%moisprece% -s -d -%jours% -m *.* -c "cmd /c del @FILE

rem elimine les dossiers trop anciens du mois precedent
forfiles /p %chemin%%moisprece% -s -d -%jours% -c "cmd /c if @isdir == TRUE RMDIR /S /Q @path"


Je tiens à préciser que je ne connaissais pas le batch hier, donc soyez indulgents sur les fautes ou lourdeurs que j'ai fait.
Néanmoins, cette tâche fonctionne parfaitement sur mon windows 8, mais dès que je le passe sous Windows 7, la tâche ne supprime que les fichiers et non les dossiers.
Savez-vous pourquoi ?

Merci de votre aide :)


A voir également:

18 réponses

Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
Modifié par Quester4 le 10/05/2013 à 00:57
Bonsoir,

Je ne sais pas du tout si le code suivant fonctionne, je n'ai pas pu tester les diverses fonctions étant donné que je n'ai plus Windows. J'en suis désolé... Il est plus complexe, plus traditionnel (je n'avais jamais vu la commande forfiles, de toute ma « carrière » Batch).

@echo off 
setlocal enabledelayedexpansion 

rem -------------------------------------------- 
rem SUPPRESSION DES ANCIENS FICHIERS ET DOSSIERS 
rem -------------------------------------------- 

set chemin=C:\Cameras 
set %jours%=10 

set moisactu=%date:~3,2% 
set /a moisprece=%moisactu%-1 

set /a limiteD=%date:0,2%-%jours% 
if !limiteD!<=0 ( 
  set /a limiteM=%moisprece% 
  set /a limiteD+=30 
) else set limiteM=%moisactu% 

for %%a in (Juanary February March April May June July August September October November December) do ( 
  set /a count+=1 
  if !moisprece!==!count! ( 
    set limiteMOld=%%a 
    set limiteMAct=%%b 
  ) 
) 
if !limiteM!==0 ( 
  set limiteMOld=December 
  set limiteMAct=Juanary 
) 
echo The previous mouth was %moisprece%, now we are in %moisactu%. 

cd %chemin% 
for /r %limiteMOld% %%a in (*) do ( 
  call :verif %limiteMOld%\%%a 
) 
for /r %limiteMAct% %%a in (*) do ( 
  call :verif %limiteMAct%\%%a 
) 
echo Les fichiers de plus de %jours% jours dans %chemin% ont ete supprimes. 
pause 
exit 

:verif 
set T[%1]=%~t1 
for /f "tokens=* delims=/" %%a in ("!T[%1]!") do ( 
  if %%b<!limiteM! del /q /f %1 
  if %%a<!limiteD! if %%b=!limiteM! del /q /f %1 
) 
if not exist %1 echo %1>>deleted_files.log 
goto :eof

Le code est un peu sale, et pourrait être réduit. Encore une fois, je ne suis pas sûr qu'il fonctionne bien.

Voici son fonctionnement :

Activation de l'expansion retardée des variables (j'expliquerai ceci plus tard) : setlocal.
Commentaire.
Définition des variables telles que le chemin ou la limite de jours.
Définition d'une limite de jours (limiteD) et d'une limite de mois (limiteM).
Définition des noms des mois (limiteMOld et limiteMAct).

Pour chaque fichier dans le dossier %limiteMOld% (exemple, December), appel de la fonction verif avec en paramètre le chemin (%limiteMOld%\%%a).
Verif regarde la date du fichier, et le supprime si sa date est inférieure aux limites. Tous les fichiers plus anciens que la limite de mois sont supprimés, puis tous les fichiers plus anciens que la limite de jours dans la limite de mois (exemple : tout ce qui est avant le 17/09).
Si le fichier a été supprimé, donc qu'il n'existe plus, alors ça ajoute son nom au fichier deleted_fils.log.
Puis retour à la boucle For ayant appelé, pour refaire ça avec tous les autres fichiers.


Si quelque chose est mal expliqué, je pourrais vous en parler plus en détail, n'hésitez-pas ;)
1
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
Modifié par Quester4 le 10/05/2013 à 14:23
Il me semble qu'en allant vite, j'ai fait quelques erreurs, comme cette ligne :
set %jours%=10
Qu'il faut remplacer par :
set jours=10

Pour plus de lisibilité par rapport à ton ancien code, tu peux remplacer limiteMOld par moisprece, et limiteMAct par moisactu.

D'ailleurs, il me semble que j'ai oublié la suppression de dossiers, que voici :
for /f "delims=""" %%i in ('dir "%chemin%" /b /s') do ( 
 if %%~xiB==B ( 
  set fichier=0 
  for /f "delims=""" %%j in ('dir "%%i" /b /s') do set /a file+=1
  if !file! NEQ 0 rmdir "%%i" /s /q  
  )  
) 

PS : Ce code est celui de Bilou (cs-bilou), dans ce sujet.

J'aurais plutôt proposé plutôt un code comme celui-ci :
call :delfolders !limiteMOld!
call :delfolders !limiteMAct!
echo Les dossiers vides de %chemin% ont ete supprimes.
pause
exit

:delfolders
for /f "tokens=4,5,6,7" %%a in ('dir "%1"') do (
  set "foldername=%1\%%a"
  for %%n in (%%b %%c %%d) do if defined %%n set "foldername=!foldername! %%n"
  for /f "tokens=4,5,6,7" %%g in ('dir "!foldername!"') do (
    set "subfoldername=!foldername!\%%g"
    for %%n in (%%h %%i %%j) do if defined %%n set "foldername=!foldername! %%n"
    rd !suberfoldername!
)
  rd !foldername!
)
goto :eof
0
Très bien, je vais essayer ça.
Merci de ton aide, je te tiens au courant
0
J'ai essayer de comprendre le fonctionnement du programme, je ne comprends pas tout, par exemple le %%a ou les !! devant et derrière une variable. (Car comme je l'ai dit plus haut, je découvre cet environnement ^^ )
Quand j'essaye de le lancer, la console m'indique :
Nombre non valide. Les constantes numériques doivent être soit décimales <17>, soit héxadécimales <0x11>, soit octales <021>.
0
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
11 mai 2013 à 11:56
Les points d'exclamation au lieu des %, autour d'une variable, permettent d'utiliser l'expansion retardée. Avec l'expansion retardée, la console va considérer une variable de format !x! comme étant une chaîne, donc les guillemets ne sont plus toujours nécessaires (comme par exemple avec les If).
Mais aussi, quand tu changes la valeur d'une variable dans une boucle For, tant que la boucle n'est pas finie, la valeur de la variable sera considérée comme étant la même avec les %x%. Avec l'expansion retardée, la variable sera changée directement, ce qui te permet d'utiliser des valeurs différentes à chaque fois (comme par exemple la variable count dans la boucle qui définit le mois.
__________________________________________

Ensuite, pour ce qui est des %%a, il s'agit de la syntaxe des boucles For. Une boucle For est assez difficile à comprendre paraît-il... Il s'agit d'une sorte de condition, qu'on pourrait traduire en langage naturel par :
Pour toutes les valeurs de A dans (ensemble entre parenthèses), faire (
  ...
  ...
)

La syntaxe de la variable A, ici, est %%A. Cette variable est définie seulement durant le temps d'exécution de la boucle ; la syntaxe d'ailleurs est spécifique aux boucles For, tu ne peux pas l'utiliser en-dehors.
Et donc, cette « variable » va prendre successivement toutes les valeurs indiquées dans les parenthèses, avec l'espace ou la virgule délimitant les valeurs.
Par exemple, dans (A B C D E), %%a prendra successivement les valeurs A, B, C, D, et E, à chaque passage dans la boucle. Au contraire, dans (AB CD E), il n'y a que trois valeurs : AB, CD, et E. Par contre, tu peux faire quelque chose comme ceci : ("AB CD" EF GH), ce qui considérera "AB CD" comme une chaîne (dû aux guillemets). Il y aura donc AB CD, EF, et GH.

Ensuite, tu n'es pas obligé de mettre forcément toutes les valeurs comme ça ; il y a des paramètres.
Le For /F te permet d'utiliser au choix une chaîne, une commande, ou un fichier. Avec une syntaxe précise pour indiquer l'ensemble choisi :
for /f %%a in (fichier) do (
for /f %%a in ("chaine") do (
for /f %%a in ('commande') do (

La commande est donc entre « guillemets simples » (ce qu'on utilise comme apostrophes), la chaîne entre guillemets anglais (les "..."), et le nom de fichier (avec éventuel chemin) sans rien.

Sinon, le for /L te permet de faire quelque chose signifiant "Pour %%a allant de x à x, avec un pas de x". Concrètement :
for /l %%a in (4,2,48) do (

Dans cette boucle, %%a va prendre toutes les valeurs comprises entre 4 et 48, avec un pas de 2 entre chaque valeur.

Encore ensuite, tu as le for /R, bien plus rarement utilisé, qui indique une action récursive dans les sous-dossiers par exemple. Tu as aussi le for /D je crois, que je n'ai jamais utilisé.

Il faudrait aussi que je t'explique le fonctionnement des "tokens= delims=" du For /f, mais je n'ai pas beaucoup de temps...

Si tu as besoin aussi de savoir comment fonctionne une boucle, car je crois avoir omis ce détail, en fait, pour toutes les valeurs de a, le contenu entre les parenthèses (après le Do) est exécuté. Tu n'es pas obligé d'utiliser %%a, ça peut être utile pour avoir 50 itérations d'une même commande, ou série de commandes.
__________________________________________

Je suppose que la troisième chose que tu n'as pas compris, c'est le %1. Le %1 est le paramètre de la commande Call, qui fonctionne comme ceci :
call :label parametre1 parametre2 parametre3

:label
echo Le premier parametre est %1, le deuxieme est %2, et le troisieme %3.

À noter que les paramètres sont au maximum 9. C'est pratique notamment pour faire des opérations relatives aux fichiers, car ça te permet de connaître la taille (%~t1), dans le cas présent (je n'ai pas le reste de la liste en tête).

Ce message était relativement très long, mais au moins j'espère qu'il t'aura été utile ^^'.

Maintenant, le problème de ce code... Peux-tu me dire environ à quelle ligne il se situe ? Si tu ne peux pas, essayes de lever le @echo off, et de mettre des pause entre les commandes, pour que la console t'affiche la ligne qui pose problème.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Tout à fait utile ! Je ne sais pas quoi dire d'autre que merci ! =)

J'ai mis un pause entre chaque actions, le programme se ferme à partir de :
if !limiteD!<=0 (
set /a limiteM=%moisprece%
set /a limiteD+=30
) else set limiteM=%moisactu%

Pour la faute de la variable, il manquait juste un ~devant 0.2%.
0
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
11 mai 2013 à 13:24
Essaies en remplaçant la ligne :
set /a limiteM=%moisprece% 

Par la ligne :
set limiteM=%moisprece% 
0
J'ai trouvé ce qu'il n'allait pas, il n'aimait pas le <= , je l'ai remplacé par un LEQ.
Maintenant il bug au niveau de la boucle for :s
0
J'ai cette fenêtre http://img16.imageshack.us/img16/6185/sanstitreitc.png
0
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
Modifié par Quester4 le 11/05/2013 à 15:14
Hum, c'est assez étrange, on dirait que le Batch a ignoré une bonne partie du code...
J'ai refait une bonne partie du code, j'ai corrigé quelques erreurs qui effectivement doivent faire planter le programme (je suis vraiment désolé de ne pas pouvoir débugger le script moi-même :/).
@echo off    
setlocal enabledelayedexpansion    

rem --------------------------------------------    
rem SUPPRESSION DES ANCIENS FICHIERS ET DOSSIERS    
rem --------------------------------------------    

set chemin=C:\Cameras    
set jours=10    

set moisactu=%date:~3,2%    
set /a moisprece=%moisactu%-1    

set /a limiteD=%date:~0,2%-%jours%    
if !limiteD!<=0 (    
  set limiteM=%moisprece%    
  set /a limiteD+=30    
) else set limiteM=%moisactu%    

for %%a in (Juanary February March April May June July August September October November December) do (    
  set /a count+=1    
  if !limiteM!==!count! set limiteMname=%%a   
)    
if !limiteM!==0 set limiteMname=December   

echo The previous mouth was %moisprece%, now we are in %moisactu%.    

for /r !chemin!\!limiteMname! %%a in (*) do (    
  call :verif "%limiteMname%\%%a"   
  if not exist "%limiteMname%\%%a" echo %1>>deleted_files.log    
)   
for /r !chemin!\!limiteMname! %%a in (*) do rd "!chemin!\!limiteMname!\%%a"   
echo Les fichiers de plus de %jours% jours dans %chemin%\%limiteMname% ont ete supprimes.    
pause    
exit    

:verif    
set T[%1]=%~t1   
for /f "tokens=* delims=/" %%a in ("!T[%1]!") do (    
  if %%b LSS !limiteM! del /q /f %1    
  if %%a LSS !limiteD! if %%b==!limiteM! del /q /f %1    
)   
goto :eof

Donc, en erreurs corrigées, j'ai mis des LSS à la fin, dans verif, étant donné que le "<=" ne marche pas j'ai préféré ne pas prendre de risques. J'avais oublié un =, à la condition "if %%b==!limiteM!", ce qui fait assurément planter le code.
J'ai aussi restreint les fichiers recherchés, maintenant le Batch va juste chercher les fichiers dans le mois limite (soit le mois actuel soit le mois précédent), pas les deux.
Au fait, la suppression de sous-dossiers vides est dans cette ligne :
for /r !chemin!\!limiteMname! %%a in (*) do rd "!chemin!\!limiteMname!\%%a"

Je suis vraiment désolé de pas pouvoir tester tout ça tout seul :/
0
Ne t'inquiète pas, tu m'aide c'est déjà très sympa de ta part :).
Suite à ce que tu as mis en commentaire, la recherche se fera soit dans un Mois soit dans l'autre.
Ca correspond simplement au nombre de jour qui fait office de seuil.
Par exemple si nous sommes le 3 Juin. Le programme va bien chercher que dans le mois de Mai ?
0
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
11 mai 2013 à 16:00
Oui, si tu es le 3 Juin, ça va chercher dans le mois de Mai, pas dans le mois de Juin, donc c'est plus rapide. Par contre si tu es le 11 Juin, ça va chercher dans le mois de Juin et pas dans le mois de Mai... Dans tous les cas, c'est plus rapide, mais beaucoup de fichiers risquent d'être ignorés.
0
Ignorés si il y a 31 jours ou 28/29 (pour Février) par exemple ?
0
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
Modifié par Quester4 le 11/05/2013 à 17:49
Hum, effectivement, ces cas de figure doit être pris en compte.
Dans les lignes :
set /a limiteD=%date:~0,2%-%jours%      
if !limiteD! LEQ 0 (      
  set limiteM=%moisprece%      
  set /a limiteD+=30      
) else set limiteM=%moisactu%      

for %%a in (Juanary February March April May June July August September October November December) do (      
  set /a count+=1      
  if !limiteM!==!count! set limiteMname=%%a     
)      
if !limiteM!==0 set limiteMname=December

Il faut remplacer par :
set /a limiteD=%date:~0,2%-%jours%  
set limiteM=%moisactu%  
if !limiteD! LEQ 0 set limiteM=%moisprece%  

for %%b in (0 1 3 5 7 8 10 12) do if !limiteM!==%%b set add=31  
for %%b in (4 6 9 11) do if !limiteM!==%%b set add=30  
if !limiteM!==2 (  
  set sub=28  
  set year=%date:~6,4%  
  for /l %%a in (1,1,20) do (  
    set yearV=2008+%%a*4  
    if !yearV!==!year! set add=29  
  )  
)  
if !limiteD! LEQ 0 set /a limiteD+=%add%  

for %%a in (Juanary February March April May June July August September October November December) do (  
  set /a count+=1  
    if !limiteM!==%%a set limiteMname=%%a  
  )  
)  
if !limiteM!==0 set limiteMname=December

Note : pour le mois de Février, j'utilise la règle du calendrier Julien, qui est qu'une année est bissextile tous les 4 ans. Elle est fausse, la vraie règle (celle actuelle) est la même, sauf que le début de chaque siècle (1900, 2100) n'est pas bissextile, à part ceux multiples de 400 (2000, 2400...). À notre échelle, la différence n'est donc pas importante, sauf si quelqu'un utilise toujours ce code en 2100.
0
voilà, j'inclus toutes les parties que tu m'a donné, tout semble fonctionner sauf la partie suppression à proprement dite voici :
http://img801.imageshack.us/img801/9196/sanstitre2fd.png
0
On viens de me dire que mon programme (celui en tout début de post) fonctionne sur Windows 7, mais ne supprime que les fichiers de plus de x jours, et pas les dossiers, il faut donc juste que j'arrive à supprimer les dossiers sans forfile ( et les fichiers aussi) la structure :

:verif
set T[%1]=%~t1
for /f "tokens=* delims=/" %%a in ("!T[%1]!") do (
if %%b LSS !limiteM! del /q /f %1
if %%a LSS !limiteD! if %%b==!limiteM! del /q /f %1
)

fonctionnerait-elle ?
Je suis désolé de t'en informer mais on viens de me faire remonter l'info il y a 1 heure et demi
0
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
Modifié par Quester4 le 11/05/2013 à 21:29
Je ne suis pas sûr que l'on puisse voir la date des dossiers...
Par contre, vu que les fichiers présents dans les dossiers sont supprimés, tu peux supprimer les dossiers vides (avec le code de Bilou posté plus haut par exemple) :
for /f "delims=""" %%i in ('dir "%chemin%\%limiteMname%" /b /s') do (  
 if %%~xiB==B (  
  set fichier=0  
  for /f "delims=""" %%j in ('dir "%%i" /b /s') do set /a file+=1  
  if !file! NEQ 0 rmdir "%%i" /s /q  
  )    
) 
0
Super, ca marche !
Un grand grand merci à toi, tu m'a appris pas mal de choses et m'a beaucoup aidé au niveau code =)
MERCI ENCORE =) =) =)
0
Quester4 Messages postés 134 Date d'inscription mercredi 8 février 2012 Statut Membre Dernière intervention 18 juillet 2013 125
11 mai 2013 à 23:24
Hum, de rien ^^
Penses à marquer ton sujet comme étant résolu =)
0