2017-08-04 148 views
3

如果计数j达到0,我不想离开for循环。批量退出for循环

set /a j=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 %%i c:\dsd_imports\ad_and_deal\in_process 
    set /a j=j-1 
    if j == 0 
    break 
) 
+3

'break'不成批处理。使用“goto”。 – SomethingDark

+0

批次中的'if'必须在一行中,变量必须使用'%%'扩展。 '如果j == 0'是一个语法错误 –

+0

谢谢,我只是不熟悉if语句的语法。你能提供确切的语法吗?是否如果%% j = 0转到这里 –

回答

0

转到将退出FOR代码。此外,您必须使用延迟的环境变量扩展来测试您的循环控制变量,因为FOR块在执行前完全是%var%扩展的。事情是这样的:

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

不使用调用运行不同的.bat会中断批处理。 – LotPings

+0

我阻止复制(并忽略)该问题的.bat调用,添加“for break”示例逻辑。我已经进一步简化了回应。 –

3

这里是你的批号改写,评论说:

@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 string comparison (a few microseconds faster than an integer 
rem comparison as environment variables are always of type string) 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 

我希望你不要真的需要在C:\dsd_imports\ad_and_deal因为这递归处理的文件会导致处理也文件已在子目录in_process中处理。

为了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。

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

大约值与IF

IF等于操作员在一个字符串比较而操作者==结果总是比较的额外信息EQU第一总是试图整数的比较,并且如果这是不可能的也执行字符串比较,因为它可以与被证明:

@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) 

上执行的输出是:

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

在间歇以上代码围绕参数!FileCount!0的双引号可以安全地移除,但并非总是如此,但在这里。

我添加了双引号,以使每个人都清楚字符串是否被比较,因为两个参数的双引号也被比较。

==操作者的IF可以在Ç进行编码,例如用如下代码:

#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; 
} 

所以使用"!FileCount!" == "0"!FileCount! == 0所不同的是strcmp具有比较4与2个字节包括终止空字节。这并没有真正的区别,因为可以通过修改上面的代码来证明它,并且在循环中运行例如100.000.000次的strcmp并且测量执行时间,并且一次又一次地在核心/处理器的高速缓存中进行比较。

SETLOCALENDLOCAL内的使用情况循环,而不是外界使得在下半部中进行了描述,因为这两个命令来完成的所有操作的批处理文件执行完毕所需要的时间差this answer

那么快就肯定:

@echo off 
setlocal EnableExtensions EnableDelayedExpansion 
set "FileCount=3" 
cd /D C:\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 

但是,如果通过发现任何文件中包含1个或多个感叹号这个快批代码不起作用。原因是文件名中的第一个!被解释为延迟的环境变量引用的开始,如果没有第二个!被解释为延迟的环境变量引用的结束以及这两个之间的字符串,则从文件名中删除该文件名中的字符串!在调用另一个批处理文件之前,扩展%%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 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 

在Windows XP和Windows 7运行这个批处理文件的输出是:

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" 

为了完整相当于C运营商代码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; 
} 

这里可以已经看到的用于演示EQU行为与C代码上面阐述了所引起的更多的CPU指令使用EQU结果整数的比较比上做一个串正在执行使用==比较==行为比较该C代码运营商。在以单步模式运行应用程序时,也将其应用到标准库函数strcmpstrtol中,更明确一点的是,处理器必须执行更多指令才能在批处理文件中运行比字符串比较更多的整数比较。

写在Ç这第二个应用程序演示了完美的东西经常发生意外的批处理文件编写者使用数字在批处理文件1个或以上前导零上的字符串值与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 
equ.exe 0x14 20 
equ.exe 0x14 \"20\" 

结果我与equ.exe与GPP 4.7.3(DJGPP封装)编译得到的是:

"08" EQU "08" 
The strings are equal. 
08 EQU 8 
The strings 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 strings are different. 

第一比较"08" EQU "08"由于两个参数中的"都作为字符串比较执行。

第二比较08 EQU 8因为第一个参数具有前导0开始,并因此由函数strtol与第三参数base0为八进制数,其是因为包含的无效解释最终还执行作为字符串而不是作为整数比较数字8.有效的八进制数字只有0-7范围内的数字。所以字符串到长整数的转换失败,因此与8相比,08的字符串比较被执行。

第三个比较14 EQU 14是作为整数比较执行的,两个数字都被解释为十进制数。

第四个比较014 EQU 014也作为整数比较执行,但两个数字都被解释为八进制。

第五次比较0x14 EQU 0x14再次作为整数比较执行,但两个数字被解释为十六进制解释两次20作为输出编号。

因此,建议尽可能使用运算符==以及不使用或使用明确围绕的双引号来在批处理文件中运行两个值的字符串比较。

这是绝对没用使用批处理文件来衡量==时间差与EQU,因为Windows命令解释程序所需要的时间来执行IF条件之前在批处理文件中的命令行解析为许多倍量比较本身所需的时间,正如内部使用的编译C/C++代码所证明的那样。

当然这也意味着使用==EQU对于完成批处理文件完成的任务所需的总时间并没有给用户带来真正的区别。但除了执行时间使用==EQU之外的其他原因经常会有所不同。

+0

出于好奇,我以'if'!FileCount为基准!“ ==“0”endlocal&goto完成行1,000,000次,在我的64位Win 7框中带和不带引号。结果是相同的(121,000毫秒)。我想这是预料之中的,因为那是一个带或不带引号的字符串比较。所以我用'EQU'替换了未引用的版本'==',并再次获得了相同的结果。我测量的唯一显着差异是使用'!FileCount!'比使用'%FileCount%'慢10%(同样,计时一百万次)。看起来像是这个额外的传球,如果一个巨大的标志存在就会有所作为。 –