在 FOR 循环中,批处理 %errorlevel% 返回值为 0。

3
我正在尝试编写一个循环,从指定的目录中读取一系列文本文件并查找特定的字符串。根据是否找到该字符串报告结果。但是%errorlevel%总是返回0并且值为0。
SETLOCAL enabledelayedexpansion

    FOR %%G IN (*.txt) DO (
        find /i "My text string" "%%G"
        ECHO %date% %time% :  errorlevel is %errorlevel% >> %report_dir%\%computername%.txt
        IF %errorlevel% EQU 1 (
            ECHO %date% %time% : String found >> %report_dir%\%computername%.txt

            GOTO:copy_log
        )

    )

    ENDLOCAL

Raymond,你的意思是什么?:

SETLOCAL enabledelayedexpansion

    FOR %%G IN (*.txt) DO (
        find /i "My text string" "%%G"
        IF %errorlevel% (
            ECHO %date% %time% : String found >> %report_dir%\%computername%.txt

            GOTO:copy_log
        )

    )

    ENDLOCAL

1
正如文档中所述,您可以使用感叹号进行延迟扩展,百分号进行立即扩展。您仍在使用%ERRORLEVEL%,这将被立即扩展。您需要延迟扩展,因此需要!ERRORLEVEL!。或者,您可以通过说IF ERRORLEVEL 1来避免整个问题。 - Raymond Chen
4个回答

8

%ERRORLEVEL%的展开时间过早了。你可以通过使用以下方法完全避免这个问题:

IF ERRORLEVEL 1

或者更详细的信息,请参见“SET /?”帮助文本中关于“延迟环境变量扩展”的说明:

Finally, support for delayed environment variable expansion has been added. This support is always disabled by default, but may be enabled/disabled via the /V command line switch to CMD.EXE. See CMD /?

Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed. The following example demonstrates the problem with immediate variable expansion:

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "%VAR%" == "after" @echo If you see this, it worked
    )

would never display the message, since the %VAR% in BOTH IF statements is substituted when the first IF statement is read, since it logically includes the body of the IF, which is a compound statement. So the IF inside the compound statement is really comparing "before" with "after" which will never be equal. Similarly, the following example will not work as expected:

    set LIST=
    for %i in (*) do set LIST=%LIST% %i
    echo %LIST%

in that it will NOT build up a list of files in the current directory, but instead will just set the LIST variable to the last file found. Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:

    for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "!VAR!" == "after" @echo If you see this, it worked
    )

Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:

    for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "!VAR!" == "after" @echo If you see this, it worked
    )

    set LIST=
    for %i in (*) do set LIST=!LIST! %i
    echo %LIST%

5

我更喜欢让For循环调用分支。这可以防止变量扩展问题:

For %%G In (*.txt) Do Call :ScanFile "%%G"
Exit /B

:ScanFile
Find /i "My text string" "%~1"
If %ErrorLevel%==1 (
    Echo %date% %time% : String found >> %report_dir%\%computername%.txt
    Goto :CopyLog
)
Exit /B

:CopyLog
...
Exit /B

这是最简单的解决方案。谢谢。 - Dean

2

正如Raymond所说,你正在评估echo的%ERRORLEVEL%,它几乎总是(永远不要说从不)返回0。

以下类似的内容会更好:

FOR %%G IN (*.txt) DO (
    find /i "My text string" "%%G"
    SET error = %errorlevel% 
    ECHO %date% %time% :  errorlevel is %errorl% >> %report_dir%\%computername%.txt
    IF %error% EQU 1 (
        ECHO %date% %time% : String found >> %report_dir%\%computername%.txt
        GOTO:copy_log
    )
)

0

我在循环注册表键/值时遇到了同样的问题,并来到了这篇文章。我的“reg query”在for循环中总是有ERRORLEVEL 0。

以下是我的解决方案:

for %%s in (%ToBeUninstalled%) do ( REG QUERY "%KEY64%\%%s" | find /i "UninstallString" > NUL && (msiexec.exe /x %%s /qb) || (echo Software not installed) )

其中KEY64为HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接