本文介绍了批量退出for循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 如果 j 达到 0,我不想为循环留下 。 set / aj = 3 for / R c:\dsd_imports\\ (*。*)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 ) 解决方案这里是您的批处理代码重写和评论: @echo off rem定义环境变量FileCount的值为3. 设置FileCount = 3 rem在堆栈上推送当前目录的路径, rem当前目录中的所有内容,直至命令POPD。 pushd C:\dsd_imports\ad_and_deal rem在所有非隐藏文件上指定的目录中进行处理。 rem为每个文件调用另一个带有当前文件名称的批处理文件。 rem然后将当前文件移动到子目录in_process中,并将 rem文件计数变量减1。 rem启用延迟扩展,从而创建副本把所有的环境变量都删除,再次将当前目录推到堆栈 rem。 rem运行字符串比较(比整数 rem比较快几个微秒,因为环境变量总是字符串类型)为 rem确定是否已经处理了3个文件这种情况下,循环 rem退出时跳转到循环下方的标签。 rem在任何情况下,必须使用命令 rem ENDLOCAL在批处理文件执行继续执行标签Done或 rem之前使用循环执行来恢复以前的环境。 (*)do()调用MDI_import_ad_command.bat%% I move / Y%% Iin_process \ set / A FileCount- = 1 setlocal EnableDelayedExpansion 如果!FileCount!==0endlocal& goto完成 endlocal ) rem删除不再需要的环境变量FileCount。 rem然后从堆栈中弹出以前的当前目录路径,并使将该目录再次移动到批处理文件剩余的当前目录。 :完成设置FileCount = popd 我希望你不需要递归地处理 C:\dsd_imports\ad_and_deal 中的文件,因为这样会导致处理子目录中已经处理的文件 in_process 。 为了解所使用的命令及其工作方式,请打开命令提示符窗口,命令,并仔细阅读每个命令显示的所有帮助页面。 call /? $ li $ echo /? endlocal /? 转到/? if /? move /? code> popd /? pushd /? rem /? set /? setlocal /? 额外信息a回合比较值与IF IF 等于运算符 == 结果总是以字符串形式进行比较,而运算符 EQU 第一个总是尝试一个整数比较,如果不可能的话也执行一个字符串比较,因为它可以被证明如下: @echo off 如果00 == 0(使用==时echo 00等于0)else(echo 00 is different 0使用==)如果00 EQU 0(使用EQU时echo 00等于0)else(使用EQU时echo 00不等于0) 执行的输出是: 00在使用= = 00在使用EQU 时等于0在上面的双引号参数!FileCount!和 0 可以被安全地移除,但并不总是这样,但是在这里。 / p> 我添加了双引号,让每个人都清楚字符串被比较,因为使用双引号将两个参数进行比较。 $ b $ c == / strong>可以在 C 中编码,例如: #include< stdio.h> #include< string.h> $ b $ main(int argc,char * args []) { if(argc!= 3) { puts(Error:这个比较演示只需要两个参数。); 返回2; $ b $注意:在调用函数main之前执行的用于编译器的可执行文件被添加的启动代码删除了最可能的参数周围的双引号字符串。 以\value\形式指定参数,以将参数与周围的双引号进行比较。 * / printf(比较%s与%s.\\\,args [1],args [2]); $ b $ if(strcmp(args [1],args [2])== 0) { puts(The strings are equal。); 返回0; } puts(字符串不同); 返回1; $ / code> 所以使用!FileCount! ==0与!FileCount! == 0 是 strcmp 必须比较4与2字节,包括终止的空字节。这并没有真正的区别,因为通过修改上面的代码可以证明这一点,并且在一个循环中运行 strcmp 例如100.000.000次并且再次测量执行时间并在核心/处理器的缓存中再次进行比较。 $ b SETLOCAL 和 ENDLOCAL 因为这两个命令所做的所有操作(如 循环并不会影响批处理文件执行完成所需的时间。 / b / b / a / 38676582/3074564>这个答案。 所以速度会更快: setlocal EnableExtensions EnableDelayedExpansion setFileCount = 3 cd / DC:\dsd_imports\ad_and_deal $ b (*)do( call MDI_import_ad_command.bat%% I move / Y%% Iin_process \ set / A FileCount- = 1 if!F ileCount!== 0转到完成) :完成 rem在这里添加其他命令。 rem此命令销毁环境变量的本地副本, rem意味着如果在运行 rem此批处理文件之前不存在FileCount,则不会再存在。它还使用命令CD恢复以前的当前目录改变 rem。 endlocal 但是这个快速的批处理代码不起作用, FOR 包含一个或多个感叹号。原因是文件名中的第一个!被解释为延迟的环境变量引用的开始,如果没有第二个 !被解释为延迟环境变量引用的结束,文件名中这两个!之间的字符串将被替换 %% I 在调用另一个批处理文件之前。 这个总是不需要的行为可以通过运行这个批处理文件: @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默认情况下禁用延迟扩展: echo / %for %% I in(%TEMP%\File *)do echo%%〜nxI echo / echo显式启用延迟扩展:回声/ setlocal EnableExtensions EnableDelayedExpansion 为%%我在(%TEMP%\文件*)回声%%〜nxI endlocal del%TEMP%\File *> nul echo / pause 在Windows XP和Windows 7上执行的这个批处理文件的输出是: 默认情况下: File!1.txtFile!2!.txtFile!XYZ!abc!.txt 显式启用延迟扩展: 文件1.txt文件.txt文件abc.txt 的等价 C : #include #include< stdlib.h> #include< string.h> $ b int main(int argc,char * args []) { char * psEnd; long int lArgument1; long int lArgument2; $ b $ if(argc!= 3) { puts(错误:这个比较演示只需要两个参数。 返回2; $ b $ *注意:在调用函数main之前执行的用于编译器的可执行文件被添加的启动代码删除了最可能的参数中的双引号字符串。 以\value\形式指定参数,以将参数与周围的双引号进行比较。 * / 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(字符串相等); 返回0; } puts(字符串不同); 返回1; } lArgument2 = strtol(args [2],& psEnd,0); if(* psEnd!='\0') { if(strcmp(args [1],args [2])== 0) { puts(字符串相等); 返回0; } puts(字符串不同); 返回1; if(lArgument1 == lArgument2) { printf(整数%ld和%ld是相等的。\ n,lArgument1,lArgument2 ); 返回0; } printf(整数%ld和%ld是不同的。\ n,lArgument1,lArgument2); 返回1; $ b 比较这个C代码来演示 EQU 行为与上面的C代码演示 == 行为,使用 EQU 会导致执行更多的CPU指令,比使用 == 运算符进行字符串比较要多。在单步模式下运行应用程序也可以使用标准库函数 strcmp 和 用 C 编写的第二个应用程序显示了批处理文件编写者使用数字在批处理文件中包含一个或多个前导零,用于比较 EQU 的值或在算术表达式中使用它们,即在 set / A 。 例如,将上面的代码编译为 equ.exe 并运行以下命令: @echo off equ.exe \08 \\08 \ equ .exe 08 8 equ.exe 14 14 equ.exe 014 014 equ.exe 0x14 0x14 $ b $ equ.exe 0x14 20 $ b $ equ.exe 0x14 \20 \ 使用gpp 4.7.3(DJGPP包)编译得到的结果是 equ.exe : 08EQU08字符串相等。 08 EQU 8 字符串是不同的。 14 EQU 14 整数14和14相等。 014 EQU 014 整数12和12相等。 0x14 EQU 0x14 整数20和20相等。 0x14 EQU 20 整数20和20相等。 0x14 EQU20字符串不同。 第一个比较08EQU08在这两个参数中都是作为字符串比较执行的。 第二个比较 08 EQU 8 最后也作为字符串执行,而不是整数比较,因为第一个参数以前导0开始,因此被函数 strtol 第三个参数 base 为 0 为八进制数,由于包含数字8,因此八进制数是无效的。因此,字符串到长整数的转换失败,因此,为 08 比较 8 第三个比较 14 EQU 14 被执行为整数比较,两个数字被解释为十进制。 第四个比较 014 EQU 014 也作为整数比较执行,但是两个数字都是interp第二个比较 0x14 EQU 0x14 被再次执行为整数比较,但是两个数字都被解释十六进制解释两次 20 作为输出数字。 因此,建议始终运行两个值的字符串比较批处理文件尽可能使用运算符 == 和不使用或使用明确围绕双引号。 无用的方法是使用批处理文件来测量 == 与 EQU 之间的时间差异,因为Windows命令解释器解析所需的时间在执行 IF 条件之前,批处理文件中的命令行比内部使用的已编译的C / C ++代码显示的比较本身所需的时间长少许多。 / p> 当然这也意味着使用 == 或者 EQU 对用户rega没有真正的区别使用批处理文件完成任务所需的总时间。但是,除了执行时间之外,使用 == 或 EQU 常常会有所不同。 I wan't to leave the for loop if the count j reaches 0.set /a j=3for /R c:\dsd_imports\ad_and_deal %%i IN (*.*) DO ( MDI_import_ad_command.bat C:\DSD_IMPORTS\AD_AND_DEAL\%%~nxi MOVE %%i c:\dsd_imports\ad_and_deal\in_process set /a j=j-1 if j == 0 break) 解决方案 Here is your batch code rewritten and commented:@echo offrem Define environment variable FileCount with value 3.set "FileCount=3"rem Push path of current directory on stack and make specified directoryrem the current directory for everything up to command POPD.pushd C:\dsd_imports\ad_and_dealrem 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 decrementrem the file count variable by 1.rem Enable delayed expansion which results also in creating a copy ofrem all environment variables and pushing current directory once againrem on stack.rem Run a string comparison (a few microseconds faster than an integerrem comparison as environment variables are always of type string) torem determine if 3 files were already processed in which case the looprem is exited with a jump to a label below the loop.rem In any case the previous environment must be restored with commandrem ENDLOCAL before the batch file execution continues on label Done orrem 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 makerem this directory again the current directory for rest of batch file.:Doneset "FileCount="popdI hope you don't really need to recursively process files in C:\dsd_imports\ad_and_deal as this would result in processing also the files already processed in subdirectory in_process.For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.call /?echo /?endlocal /?goto /?if /?move /?popd /?pushd /?rem /?set /?setlocal /?Extra information about comparing values with IFThe IF equal operator == results always in a string comparison while operator EQU first always tries an integer comparison and performs also a string comparison if this is not possible as it can be proven with:@echo offif 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)The output on execution is:00 is different 0 on using ==00 is equal 0 on using EQUIn the batch code above the double quotes around the arguments !FileCount! and 0 can be safely removed which is not always the case, but here it is.I added the double quotes to make it clear for everybody that strings are compared because the double quotes of both arguments are compared as well.The == operator of IF could be coded in C for example with this code:#include <stdio.h>#include <string.h>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 compiler to executable being executed before calling function main removes most likely the surrounding double quotes on the argument strings. 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 strings are equal."); return 0; } puts("The strings are different."); return 1;}So the difference on using "!FileCount!" == "0" versus !FileCount! == 0 is that strcmp has to compare 4 versus 2 bytes including the terminating null byte. This does not make a real difference as it could be proven by modifying the code above and run strcmp for example 100.000.000 times in a loop and measure the execution time for this again and again done compare in caches of the core/processor.The usage of SETLOCAL and ENDLOCAL within the FOR loop and not outside makes a difference in time required for batch file execution completion because of all the operations done by those two commands as described in bottom half of this answer.So faster would be definitely:@echo offsetlocal EnableExtensions EnableDelayedExpansionset "FileCount=3"cd /D C:\dsd_imports\ad_and_dealfor %%I in (*) do ( call MDI_import_ad_command.bat "%%I" move /Y "%%I" in_process\ set /A FileCount-=1 if !FileCount! == 0 goto Done):Donerem Add here other commands.rem This command destroys the local copy of the environment variables whichrem means FileCount does not exist anymore if it did not exist before runningrem this batch file. It also restores the previous current directory changedrem above with command CD.endlocalBut this faster batch code does not work if any file found by FOR contains 1 or more exclamation marks. The reason is that first ! in a file name is interpreted as begin of a delayed environment variable reference which is removed from file name if there is no second ! which is interpreted as end of delayed environment variable reference and the string between those two ! in file name would be replaced by most likely nothing on expanding %%I before calling the other batch file.This always unwanted behavior can be seen by running this batch file:@echo offecho 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 EnableDelayedExpansionfor %%I in ("%TEMP%\File *") do echo "%%~nxI"endlocaldel "%TEMP%\File *" >nulecho/pauseThe output of this batch file executed on Windows XP and Windows 7 is: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"For completeness the equivalent C code for operator EQU:#include <stdio.h>#include <stdlib.h>#include <string.h>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 compiler to executable being executed before calling function main removes most likely the surrounding double quotes on the argument strings. 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 strings are equal."); return 0; } puts("The strings are different."); return 1; } lArgument2 = strtol(args[2],&psEnd,0); if(*psEnd != '\0') { if(strcmp(args[1],args[2]) == 0) { puts("The strings are equal."); return 0; } puts("The strings 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;}It can be already seen here on comparing this C code for demonstrating EQU behavior with the C code above for demonstrating == behavior that an integer comparison caused by using EQU results in more CPU instructions being executed than on doing a string compare with using == operator. On running the application in single step mode also into the standard library functions strcmp and strtol it is even clearer that the processor has to do many more instructions to run an integer comparison in batch file than a string comparison.This second application written in C demonstrates perfect what happens often unexpected for batch file writers on using numbers with 1 or more leading zeros in batch file on comparing values with EQU or using them in an arithmetic expression, i.e. in string after set /A.For example compile above code to equ.exe and run following:@echo offequ.exe \"08\" \"08\"equ.exe 08 8equ.exe 14 14equ.exe 014 014equ.exe 0x14 0x14equ.exe 0x14 20equ.exe 0x14 \"20\"The result I get with equ.exe compiled with gpp 4.7.3 (DJGPP package) is:"08" EQU "08"The strings are equal.08 EQU 8The strings are different.14 EQU 14The integers 14 and 14 are equal.014 EQU 014The integers 12 and 12 are equal.0x14 EQU 0x14The integers 20 and 20 are equal.0x14 EQU 20The integers 20 and 20 are equal.0x14 EQU "20"The strings are different.The first comparison "08" EQU "08" is executed as string comparison because of " in both arguments.The second comparison 08 EQU 8 is finally also executed as string and not as integer comparison because first argument starts with a leading 0 and is therefore interpreted by function strtol with third parameter base being 0 as octal number which is invalid because of containing the digit 8. Valid octal numbers have only digits in range 0-7. So string to long integer conversion fails and for that reason a string comparison is executed for 08 compared with 8.The third comparison 14 EQU 14 is executed as integer comparison with both numbers being interpreted decimal.The fourth comparison 014 EQU 014 is executed also as integer comparison, but with both numbers being interpreted octal.The fifth comparison 0x14 EQU 0x14 is executed again as integer comparison, but with both numbers being interpreted hexadecimal explaining twice 20 as output number.So it is advisable to run always a string comparison of two values in batch files wherever possible with using operator == and without or with using explicitly surrounding double quotes.It is absolutely useless to measure time differences on == versus EQU using a batch file because the time needed by Windows command interpreter to parse the command lines in batch file before executing the IF condition is many times the amount of time required for the compares itself as demonstrated by the compiled C/C++ code used internally.Of course this also means using == or EQU does not make a real difference for the user regarding total time needed to accomplish the task done with the batch file. But for other reasons than execution time using == or EQU makes often a difference. 这篇关于批量退出for循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-14 19:28