草庐IT

windows - 批量退出for循环

coder 2024-06-04 原文

如果计数for达到j,我将不离开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
)

最佳答案

这是您的批处理代码重写和注释:

@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 中对 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必须比较4字节和2字节,包括终止空字节。这并没有什么真正的区别,因为可以通过修改上面的代码并在一个循环中运行strcmp例如100.000.000次并证明其执行时间来一次又一次地在内核/处理器的高速缓存中进行比较,从而证明这一点。

    FOR 循环内(而不是在外部)使用 SETLOCAL ENDLOCAL 会导致批处理文件执行完成所需的时间有所不同,这是因为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个或多个感叹号,则此更快的批处理代码将不起作用。原因是文件名中的第一个strcmp解释为延迟的环境变量引用的开头,如果没有第二个!解释为延迟的环境变量引用的末尾以及这两个!之间的字符串,则从文件名中将其删除。在调用另一个批处理文件之前,扩展!时,文件名几乎不会被替换。

    通过运行此批处理文件,可以看到总是有害的行为:
    @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"
    

    为了完整起见,运算符%%I的等效 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行为的C代码与上述用于演示EQU行为的C代码进行比较,与使用==运算符相比,使用EQU导致的整数比较导致执行的CPU指令多于执行字符串。在单步模式下将应用程序也运行到标准库函数strcmpstrtol中时,与字符串比较相比,处理器在批处理文件中运行整数比较需要做更多的指令,这甚至更加清楚。

    C 编写的第二个应用程序完美演示了批处理文件编写器经常发生的意外情况,即在批处理文件中使用具有1个或多个前导零的数字,然后将其与==进行比较,或者在算术表达式中(即EQU之后的字符串中)使用它们。

    例如,将以上代码编译为set /A并运行以下命令:
    @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.
    

    由于两个参数中都有equ.exe,因此第一个比较"08" EQU "08"将作为字符串比较执行。

    最后,第二个比较"也将作为字符串而不是整数比较执行,因为第一个参数以前导0开头,因此由函数08 EQU 8解释,第三个参数strtolbase为八进制数字,由于包含数字8而无效。有效八进制数字只有0-7范围内的数字。因此字符串到长整数的转换失败,因此,对008进行了字符串比较。

    第三个比较8作为整数比较执行,两个数字都解释为十进制。

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

    第五次比较014 EQU 014再次作为整数比较执行,但是两个数字都以十六进制形式解释,将0x14 EQU 0x14两次作为输出数字。

    因此,建议在可能的情况下,始终使用批处理符20而不使用或使用显式包围的双引号始终对批处理文件中的两个值进行字符串比较。

    使用批处理文件来测量====的时间差是绝对没有用的,因为Windows命令解释器在执行之前解析批处理文件中的命令行所需的时间,如果条件是许多倍于所需时间比较自身,如内部使用的已编译C/C++代码所示。

    当然,这也意味着使用EQU==对于完成批处理文件完成的任务所需的总时间对于用户而言并没有真正的区别。但是由于执行时间以外的其他原因,使用EQU==通常会有所不同。

    关于windows - 批量退出for循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45497211/

    有关windows - 批量退出for循环的更多相关文章

    1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    2. ruby - 树顶语法无限循环 - 2

      我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He

    3. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

      我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

    4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

      我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

    5. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

      我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

    6. ruby-on-rails - Rails 中的 NoMethodError::MailersController#preview undefined method `activation_token=' for nil:NilClass - 2

      似乎无法为此找到有效的答案。我正在阅读Rails教程的第10章第10.1.2节,但似乎无法使邮件程序预览正常工作。我发现处理错误的所有答案都与教程的不同部分相关,我假设我犯的错误正盯着我的脸。我已经完成并将教程中的代码复制/粘贴到相关文件中,但到目前为止,我还看不出我输入的内容与教程中的内容有什么区别。到目前为止,建议是在函数定义中添加或删除参数user,但这并没有解决问题。触发错误的url是http://localhost:3000/rails/mailers/user_mailer/account_activation.http://localhost:3000/rails/mai

    7. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

      当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

    8. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

      这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

    9. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

      目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

    10. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

      之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

    随机推荐