Quittez un pour la boucle dans le lot

Je ne veux pas quitter la boucle si le compte j atteint 0 .

 set /aj=3 for /R c:\dsd_imports\ad_and_deal %%i IN (*.*) DO ( MDI_import_ad_command.bat C:\DSD_IMPORTS\AD_AND_DEAL\%%~nxi MOVE %%ic:\dsd_imports\ad_and_deal\in_process set /aj=j-1 if j == 0 break ) 

Voici votre code de lot réécrit et commenté:

 @echo off rem Define environment variable FileCount with value 3. set "FileCount=3" rem Push path of current directory on stack and make specified directory rem the current directory for everything up to command POPD. pushd C:\dsd_imports\ad_and_deal rem Process in directory specified above all non hidden files. rem For each file call another batch file with name of current file. rem Then move current file to subdirectory in_process and decrement rem the file count variable by 1. rem Enable delayed expansion which results also in creating a copy of rem all environment variables and pushing current directory once again rem on stack. rem Run a ssortingng comparison (a few microseconds faster than an integer rem comparison as environment variables are always of type ssortingng) to rem determine if 3 files were already processed in which case the loop rem is exited with a jump to a label below the loop. rem In any case the previous environment must be restored with command rem ENDLOCAL before the batch file execution continues on label Done or rem with loop execution. for %%I in (*) do ( call MDI_import_ad_command.bat "%%I" move /Y "%%I" in_process\ set /A FileCount-=1 setlocal EnableDelayedExpansion if "!FileCount!" == "0" endlocal & goto Done endlocal ) rem Delete the environment variable FileCount as no longer needed. rem Then pop the previous current directory path from stack and make rem this directory again the current directory for rest of batch file. :Done set "FileCount=" popd 

J’espère que vous n’avez pas vraiment besoin de traiter récursivement les fichiers dans C:\dsd_imports\ad_and_deal car cela entraînerait également le traitement des fichiers déjà traités dans le sous-répertoire in_process .

Pour comprendre les commandes utilisées et leur fonctionnement, ouvrez une fenêtre d’invite de commandes, exécutez-y les commandes suivantes et lisez attentivement toutes les pages d’aide affichées pour chaque commande.

  • call /?
  • echo /?
  • endlocal /?
  • goto /?
  • if /?
  • move /?
  • popd /?
  • pushd /?
  • rem /?
  • set /?
  • setlocal /?

Informations supplémentaires sur la comparaison des valeurs avec IF

L’opérateur égal IF == entraîne toujours une comparaison de chaînes, tandis que l’opérateur EQU essaie toujours une comparaison de nombres entiers et effectue également une comparaison de chaînes si cela n’est pas possible car cela peut être prouvé avec:

 @echo off if 00 == 0 (echo 00 is equal 0 on using ==) else (echo 00 is different 0 on using ==) if 00 EQU 0 (echo 00 is equal 0 on using EQU) else (echo 00 is different 0 on using EQU) 

La sortie à l’exécution est la suivante:

 00 is different 0 on using == 00 is equal 0 on using EQU 

Dans le code de lot au-dessus des guillemets doubles autour des arguments !FileCount! et 0 peut être retiré en toute sécurité, ce qui n’est pas toujours le cas, mais le voici.

J’ai ajouté les guillemets pour que tout le monde comprenne que les chaînes sont comparées parce que les guillemets des deux arguments sont également comparés.

L’opérateur == de IF pourrait être codé en C par exemple avec ce code:

 #include  #include  int main(int argc, char* args[]) { if(argc != 3) { puts("Error: This compare demo requires exactly two parameters."); return 2; } /* Note: The startup code added by used comstackr to executable being executed before calling function main removes most likely the surrounding double quotes on the argument ssortingngs. Specify the arguments in form \"value\" to compare the arguments with surrounding double quotes. */ printf("Compare %s with %s.\n",args[1],args[2]); if(strcmp(args[1],args[2]) == 0) { puts("The ssortingngs are equal."); return 0; } puts("The ssortingngs are different."); return 1; } 

Donc, la différence sur l’utilisation de "!FileCount!" == "0" "!FileCount!" == "0" contre !FileCount! == 0 !FileCount! == 0 est que strcmp doit comparer 4 à 2 octets, y compris l’octet nul final. Cela ne fait pas vraiment de différence car cela pourrait être prouvé en modifiant le code ci-dessus et en strcmp par exemple 100 000 000 fois strcmp dans une boucle et mesurer le temps d’exécution pour cela encore et encore, comparé dans les caches du cœur / processeur.

L’utilisation de SETLOCAL et ENDLOCAL dans la boucle FOR et pas à l’extérieur fait une différence de temps nécessaire à la fin de l’exécution du fichier batch en raison de toutes les opérations effectuées par ces deux commandes comme décrit dans la moitié inférieure de cette réponse .

Si vite serait certainement:

 @echo off setlocal EnableExtensions EnableDelayedExpansion set "FileCount=3" cd /DC:\dsd_imports\ad_and_deal for %%I in (*) do ( call MDI_import_ad_command.bat "%%I" move /Y "%%I" in_process\ set /A FileCount-=1 if !FileCount! == 0 goto Done ) :Done rem Add here other commands. rem This command destroys the local copy of the environment variables which rem means FileCount does not exist anymore if it did not exist before running rem this batch file. It also restores the previous current directory changed rem above with command CD. endlocal 

Mais ce code de lot plus rapide ne fonctionne pas si un fichier trouvé par FOR contient un ou plusieurs points d’exclamation. La raison est la première ! dans un nom de fichier est interprété comme début d’une référence de variable d’environnement retardée qui est supprimée du nom de fichier s’il n’y a pas de seconde ! ce qui est interprété comme une fin de référence de variable d’environnement retardée et la chaîne entre ces deux ! dans le nom de fichier serait remplacé par probablement rien sur l’expansion %%I avant d’appeler l’autre fichier de commandes.

Ce comportement toujours indésirable peut être vu en exécutant ce fichier de commandes:

 @echo off echo File !1.txt>"%TEMP%\File !1.txt" echo File !2!.txt>"%TEMP%\File !2!.txt" echo File !XYZ! abc!.txt>"%TEMP%\File !XYZ! abc!.txt" echo With delayed expansion disabled as by default: echo/ for %%I in ("%TEMP%\File *") do echo "%%~nxI" echo/ echo With delayed expansion enabled explicitly: echo/ setlocal EnableExtensions EnableDelayedExpansion for %%I in ("%TEMP%\File *") do echo "%%~nxI" endlocal del "%TEMP%\File *" >nul echo/ pause 

La sortie de ce fichier batch exécuté sur Windows XP et Windows 7 est la suivante:

 With delayed expansion disabled as by default: "File !1.txt" "File !2!.txt" "File !XYZ! abc!.txt" With delayed expansion enabled explicitly: "File 1.txt" "File .txt" "File abc.txt" 

Pour être complet, le code C équivalent à l’opérateur EQU :

 #include  #include  #include  int main(int argc, char* args[]) { char* psEnd; long int lArgument1; long int lArgument2; if(argc != 3) { puts("Error: This compare demo requires exactly two parameters."); return 2; } /* Note: The startup code added by used comstackr to executable being executed before calling function main removes most likely the surrounding double quotes on the argument ssortingngs. Specify the arguments in form \"value\" to compare the arguments with surrounding double quotes. */ printf("%s EQU %s\n",args[1],args[2]); lArgument1 = strtol(args[1],&psEnd,0); if(*psEnd != '\0') { if(strcmp(args[1],args[2]) == 0) { puts("The ssortingngs are equal."); return 0; } puts("The ssortingngs are different."); return 1; } lArgument2 = strtol(args[2],&psEnd,0); if(*psEnd != '\0') { if(strcmp(args[1],args[2]) == 0) { puts("The ssortingngs are equal."); return 0; } puts("The ssortingngs are different."); return 1; } if(lArgument1 == lArgument2) { printf("The integers %ld and %ld are equal.\n",lArgument1,lArgument2); return 0; } printf("The integers %ld and %ld are different.\n",lArgument1,lArgument2); return 1; } 

On peut déjà voir ici la comparaison de ce code C pour démontrer le comportement d’ EQU avec le code C ci-dessus pour démontrer le comportement == qu’une comparaison d’entiers provoquée par l’utilisation d’ EQU aboutit à l’ EQU de plus d’instructions CPU qu’en utilisant == opérateur. Lors de l’exécution de l’application en mode pas à pas également dans les fonctions de bibliothèque standard strcmp et strtol, il est même plus clair que le processeur doit faire beaucoup plus d’instructions pour exécuter une comparaison d’entier dans un fichier batch qu’une comparaison de chaîne.

Cette seconde application écrite en C démontre parfaitement ce qui arrive souvent inattendu pour les rédacteurs de fichiers batch utilisant des nombres avec 1 ou plusieurs zéros dans le fichier de commandes pour comparer des valeurs avec EQU ou les utiliser dans une expression arithmétique,

Par exemple, comstackz le code ci-dessus pour equ.exe et exécutez la suite:

 @echo off equ.exe \"08\" \"08\" equ.exe 08 8 equ.exe 14 14 equ.exe 014 014 equ.exe 0x14 0x14 equ.exe 0x14 20 equ.exe 0x14 \"20\" 

Le résultat obtenu avec equ.exe compilé avec gpp 4.7.3 (package DJGPP) est le suivant:

 "08" EQU "08" The ssortingngs are equal. 08 EQU 8 The ssortingngs are different. 14 EQU 14 The integers 14 and 14 are equal. 014 EQU 014 The integers 12 and 12 are equal. 0x14 EQU 0x14 The integers 20 and 20 are equal. 0x14 EQU 20 The integers 20 and 20 are equal. 0x14 EQU "20" The ssortingngs are different. 

La première comparaison "08" EQU "08" est exécutée en tant que comparaison de chaînes à cause de " dans les deux arguments.

La deuxième comparaison 08 EQU 8 est enfin exécutée en tant que chaîne et non en tant que comparaison de nombres entiers car le premier argument commence par un 0 et est donc interprété par la fonction strtol avec le troisième paramètre base strtol à 0 Les nombres octaux valides ne comportent que des chiffres compris entre 0 et 7. Donc, la conversion de nombre entier de chaînes en entier échoue et pour cette raison, une comparaison de chaînes est exécutée pour 08 par rapport à 8 .

La troisième comparaison 14 EQU 14 est exécutée en tant que comparaison entière, les deux nombres étant interprétés en décimal.

La quasortingème comparaison 014 EQU 014 est exécutée également comme comparaison entière, mais les deux nombres étant interprétés en octal.

La cinquième comparaison 0x14 EQU 0x14 est exécutée à nouveau en tant que comparaison d’entiers, mais les deux nombres étant interprétés en hexadécimal, expliquant deux fois 20 comme numéro de sortie.

Il est donc recommandé de toujours exécuter une comparaison de chaînes de deux valeurs dans des fichiers de commandes, en utilisant autant que possible l’opérateur operator == et sans ou avec l’utilisation de guillemets doubles.

Il est absolument inutile de mesurer les différences de temps sur == par rapport à EQU utilisant un fichier de commandes car le temps nécessaire à l’interpréteur de commandes Windows pour parsingr les lignes de commandes dans un fichier batch avant d’exécuter la condition IF est plusieurs fois supérieur comme démontré par le code C / C ++ compilé utilisé en interne.

Bien sûr, cela signifie également que l’utilisation de == ou EQU ne fait pas vraiment de différence pour l’utilisateur en ce qui concerne le temps total nécessaire pour accomplir la tâche effectuée avec le fichier de commandes. Mais pour d’autres raisons que le temps d’exécution, utiliser == ou EQU fait souvent une différence.

Un goto va sortir du code FOR. Vous devez également utiliser l’extension de variable d’environnement retardée pour tester votre variable de contrôle de boucle, car le bloc FOR est complètement développé en% var avant d’être exécuté. Quelque chose comme ça:

 setlocal enabledelayedexpansion set /aj=3 for /R c:\dsd_imports\ad_and_deal %%i IN (*.*) DO ( rem ... work that needs to be done ... set /aj=j-1 if !j!==0 goto exit_for ) :exit_for