Exit the for loop in batch mode

I would not leave the loop for

if count j

reaches 0

.

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


source to share


2 answers


Here is your batch code, rewritten and commented:

@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

      

Hopefully you don't need to recursively process the files in C:\dsd_imports\ad_and_deal

, as this will also process the files already processed in the subdirectory in_process

.

To understand the commands used and how they work, open a Command Prompt window, run the following commands there, and carefully read all the help pages displayed for each command.

  • call /?

  • echo /?

  • endlocal /?

  • goto /?

  • if /?

  • move /?

  • popd /?

  • pushd /?

  • rem /?

  • set /?

  • setlocal /?


More information on comparing values ​​with IF

The IF equality operator ==

always outputs a string comparison, whereas the operator EQU

always tries to do an integer comparison first and also performs a string comparison if that is not possible, as this can be proven with:

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

      

Conclusion for execution:

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

      

In the package code above, double quotes around the arguments !FileCount!

and 0

can be safely removed, which is not always the case, but here it is.

I added double quotes to let everyone know that the strings are being compared, because the double quotes of both arguments are being compared.

The ==

IF statement can 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 when used "!FileCount!" == "0"

versus versus !FileCount! == 0

is that it strcmp

has to compare 4 versus 2 bytes including the terminating null byte. It doesn't really matter as it could be proven by modifying the above code and running strcmp

, for example, 100,000,000 times in a loop, and measure the execution time for this over and over again by making comparisons in the core / processor caches.

Using SETLOCAL and ENDLOCAL in a FOR loop rather than outside makes a difference in the time it takes to complete a batch file execution due to all the operations performed by these two commands, as described in the bottom half of this answer .

This will definitely be faster:

@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

      

But this faster batch code does not work if any file found by FOR contains 1 or more exclamation marks. The reason is that the first !

in the file name is interpreted as the beginning of a link to a slowed down environment reference, which is removed from the file name, if there is no second !

, which is interpreted as a reference to the end of the replaced environment variable and the line between the two !

in the file name will be replaced rather everything, nothing when expanding %%I

before calling another batch file.



This always unwanted behavior can be seen by running this batch file:

@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

      

The output of this batch file, executed on Windows XP and Windows 7, is as follows:

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 the operator is 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;
}

      

You can compare this C code here to demonstrate the behavior EQU

with the C code above to demonstrate the behavior ==

that an integer comparison caused by use EQU

results in more CPU commands being executed than a string is compared using an operator ==

. When the application starts in stage mode as in the standard library function strcmp and strtol , further appreciate that the CPU must perform much more instructions to start comparing an integer in the batch file, than the comparison of strings.

This second application, written in C , demonstrates the beautiful thing that is often surprising to batch file writers when using numbers with 1 or more leading zeros in a batch file when comparing values ​​with EQU

or using them in an arithmetic expression, i.e. on the line after set /A

.

For example, compile the code above equ.exe

and do the following:

@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\"

      

Result obtained with equ.exe

, compiled with gpp 4.7.3 (DJGPP package):

"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.

      

The first comparison "08" EQU "08"

is performed as a string comparison due to "

in both arguments.

The second comparison 08 EQU 8

is finally also done as a string, rather than as an integer comparison, because the first argument starts with a leading 0 and is therefore interpreted by the function strtol

, and the third parameter base

is equal to 0

an octal number which is invalid due to the fact that it contains the digit 8. Valid octal numbers only have digits in the range 0-7. Thus, no string to long integer conversion is performed, and for this reason, string comparison is performed for 08

versus 8

.

The third comparison 14 EQU 14

is performed as an integer comparison, with both numbers being interpreted as decimal.

The fourth comparison 014 EQU 014

is performed in the same way as an integer comparison, but both numbers are interpreted as octal.

The fifth comparison 0x14 EQU 0x14

is performed again as an integer comparison, but with both numbers interpreted as hex, explaining twice 20

as an output number.

Therefore, it is recommended that you always compare strings of two values ​​in batch files, where possible, using the operator ==

and without, or using explicitly surrounding double quotes.

It is absolutely useless to measure the time difference ==

versus EQU

using a batch file, because the time it takes the Windows command interpreter to parse command lines in a batch file before executing the IF condition multiplies the time it takes to compare a lot , as shown by the compiled C / C code ++ used internally.

Of course, this also means that the use ==

or EQU

does not make a real difference to the user in terms of the total time it takes to complete the task being performed on the batch file. But for reasons other than runtime using ==

or EQU

, it often matters.

+3


source


Ato will exit the FOR code. Also you should use delayed environment variable expansion to check your loop control variable since the FOR block is completely% var% expanded before it is executed. Something like that:



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

      

0


source







All Articles