如果计数器j
达到0
,我希望退出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
)
如果计数器j
达到0
,我希望退出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
)
@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
周围的双引号可以被安全地去掉,这并非总是成立,但在这里是可以的。==
运算符可以用下面的C代码编写:#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个字节。这并没有实际的区别,可以通过修改上面的代码并在循环中运行strcmp
,例如100,000,000次,并测量这些执行时间来证明这一点,这些比较在核心/处理器的缓存中进行。@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
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 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
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"
为了完整起见,以下是操作符 EQU
的等效C 代码:
#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
操作符引起的整数比较和使用==
操作符进行字符串比较时,可以在此处看到更多CPU指令被执行用于使用EQU
操作符。通过在单步模式下运行应用程序,甚至可以清楚地看到在批处理文件中进行整数比较所需的处理器指令要比字符串比较多得多,包括标准库函数strcmp和strtol。
这个用C编写的第二个应用程序完美地演示了在批处理文件中使用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\"
我使用gpp 4.7.3(DJGPP包)编译的 equ.exe
的结果是:
"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
最终也被执行为字符串而不是整数比较,因为第一个参数以前导零开头,所以被函数 strtol
解释为八进制数字,其中第三个参数 base
为 0
,这是无效的,因为其中包含数字 8。有效的八进制数字只有 0-7 范围内的数字。因此,字符串转换为长整型失败,因此对于 08
和 8
进行了字符串比较。14 EQU 14
被执行为十进制整数比较。014 EQU 014
也被执行为整数比较,但两个数字都被解释为八进制。0x14 EQU 0x14
再次被执行为整数比较,但两个数字都被解释为十六进制,解释为两次输出数字 20
。==
对两个值进行字符串比较,并且可以选择是否使用双引号将其明确括起来。==
与 EQU
的时间差异是完全无用的,因为在执行 IF 条件之前,Windows 命令解释器解析批处理文件中的命令行所需的时间比比较本身需要的时间多得多,这一点可以通过内部使用的编译的 C/C++ 代码进行证明。==
或 EQU
并不会在完成批处理文件所需的总时间方面产生真正的差异。但是出于其他原因,使用 ==
或 EQU
经常会有所不同。goto语句将退出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
break
命令没有任何作用。请使用goto
命令。 - SomethingDarkif
语句必须写在一行上,并且变量必须使用%%
进行展开。if j == 0
是一个语法错误。 - phuclv