2017-08-04 12 views
3

j0に達すると、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 gotoならば –

答えて

0

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 
+1

呼び出しを使わずに別の.batを実行するとバッチが中断されます。 – LotPings

+0

"ブレイク"の例のロジックを追加して、質問から.batコールをコピー(および無視)します。私は応答をさらに簡素化しました。 –

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等しい演算子オペレータ一方、文字列比較で常に==結果を比較に関する追加情報これを用いて証明することができるように常に整数の比較を試み、これが可能でない場合、文字列比較を行う第1 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で符号化することができる 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バイトを比較しなければならないことです終了nullバイト上記のコードを変更してループ内でstrcmp(例:100.000.000)を実行することで実証されたように実際の違いはありません。また、コア/プロセッサのキャッシュで比較を繰り返し実行するための実行時間を測定します。

の下半分に記載されているように外部ループはなくFOR 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 

しかし FOR によって発見されたファイルは、1以上の感嘆符が含まれている場合は、この高速化バッチコードは動作しません。その理由は、ファイル名中の最初の!が、遅延環境変数参照の終わりと解釈される第2の!とその2つの間の文字列であると解釈されない場合、ファイル名から削除される遅延環境変数参照の開始として解釈されるからです。!ファイル名は、他のバッチファイルを呼び出す前に、%%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にも実行すると、プロセッサは文字列比較よりもバッチファイルで整数比較を実行するためにさらに多くの命令を実行する必要があります。

Cに書かれたこの第二のアプリケーションは、文字列、すなわち、EQUとの値を比較または算術式でそれらを使用してバッチファイルで1つの以上の先頭ゼロで数字を使用してバッチファイルライターのため、多くの場合、予期しない何が起こるかを完璧に証明します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\" 

Iが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"が文字列比較として実行されます。最初の引数は、先頭の0で始まり、したがってため含有する第三のパラメータbaseが無効で8進数として0された状態で機能strtolによって解釈されるため

第2の比較08 EQU 8は、最終的に、文字列としてではなく、整数の比較として実行されます有効な8進数には、0〜7の範囲の数字しかありません。そのため、文字列から長整数への変換に失敗し、その理由から、8と比較して08の文字列比較が実行されます。

第3の比較14 EQU 14は、両方の数値が10進数で解釈される整数比較として実行されます。

第4の比較014 EQU 014は整数比較としても実行されますが、両方の数値は8進数で解釈されます。

第5の比較0x14 EQU 0x14が整数比較として再度実行されますが、両方の数値が出力番号として2回20を説明する16進数で解釈されます。

したがって、可能であればオペレータ==を使用し、明示的に囲む二重引用符を使用しないで、または二重引用符を明示的に使用して、バッチファイル内の2つの値の文字列比較を常に実行することをお勧めします。

IF条件を実行する前に、バッチファイル内のコマンドラインを解析するために、Windowsのコマンド・インタプリタによって必要な時間は、多く倍の量であるため、バッチファイルを使用してEQU==の時間差を測定することが絶対に無用です内部で使用されるコンパイル済みC/C++コードで示されているように、それ自体を比較するのに必要な時間がかかります。

もちろん、==またはEQUを使用しても、バッチファイルで行われたタスクを実行するのに必要な合計時間に関して実際の違いはありません。しかし、実行時間以外の理由で==またはEQUを使用すると、多くの場合違いがあります。

+0

好奇心をそらして私は 'if 'をベンチマークしました!FileCount!" == "0" endlocal&goto Done行は、私の64ビットWin 7ボックスに引用符をつけたものと付けないものを1,000,000回付けたものです。結果は同一(121,000ms)であった。それは文字列の引用符の有無にかかわらず、私は予想されると思います。そこで、引用符で囲まれていないバージョン '=='を 'EQU'で置き換えて、同じ結果をもう一度得ました。私が測定した唯一の違いは、 '!FileCount! 'は'%FileCount% 'を使用するよりも10%遅くなりました。バングサインが存在する場合、その余分なパスのように見えます。 –

関連する問題