批处理脚本错误级别,GOTO和IF LOOP

时间:2018-07-09 11:38:22

标签: batch-file goto

我想使用以下内容检查两个日志文件的状态。

SET/A WAITCNT=0
    :WAIT
    SET /a WAIT_TIME=%ADMIN_TIME%/%TIME_OUT%
    IF %WAITCNT% GTR %WAIT_TIME% GOTO PROBLEM 
    SET/A WAITCNT=%WAITCNT%+1   
    TIMEOUT /T %TIME_OUT% /nobreak 
    FINDSTR /C:"<Running>" %HOME_1%\%LOG_FILE%
    if %ERRORLEVEL%=="0" ( 
    ( 
        GOTO :LOG
    ) 
    ELSE GOTO WAIT

:LOG
IF %JDA_LOG_FILE%="" GOTO WWF_1
SET/A WAITCNT=0
     :WAIT
     SET /a WAIT_TIME=%ADMIN_TIME%/%TIME_OUT%
    IF %WAITCNT% GTR %WAIT_TIME% GOTO PROBLEM 
    SET/A WAITCNT=%WAITCNT%+1   
    TIMEOUT /T %TIME_OUT% /nobreak 
    FINDSTR /C:"<RUNNING>" %HOME_1%\%LOG_FILE%
    if "%ERRORLEVEL%"=="0" ( 
    ( 
        GOTO END
    ) 
    ELSE GOTO WAIT

看起来它只是在第一个if循环本身中执行,并且由于goto / call而不会进入第二个循环(我不确定)。你能帮忙吗?

2 个答案:

答案 0 :(得分:2)

if %ERRORLEVEL%=="0" GOTO :LOG

%errorlevel%(不带引号)应该与字符串"0"(带引号)完全一样吗?

使用

if "%ERRORLEVEL%"=="0" GOTO :LOG

if %ERRORLEVEL%==0 GOTO :LOG

(除了LotPings提到的ELSE Aready语法失败之外-如果只有一个命令,我就不会使用括号)

另一个提示:set /a不需要百分号:set /a var=var+1是完全有效的。还有一种增加变量的语法:

set /a var+=1

答案 1 :(得分:2)

除了代码中存在的一些语法问题(在下面列出)外,一个主要问题是您定义了两个相同的标签::WAITgoto以及call(与标签一起使用),从当前行位置向下扫描批处理文件以查找给定的标签,当到达文件末尾时,扫描继续在文件的开头,指向当前行位置。因此,即使语法问题已解决,您也不会有两个循环;它们可能会导致两个循环。相反,第一个goto :WAIT会跳到第二个标签:WAIT,第二个goto :WAIT会跳到第一个:WAIT,这是您最不可能遇到的。< / p>

解决方案非常简单:重命名标签(或其中至少一个标签)以避免重复:

set /A WAITCNT=0
:WAIT_1
    set /A WAIT_TIME=ADMIN_TIME/TIME_OUT
    if %WAITCNT% gtr %WAIT_TIME% goto :PROBLEM
    set /A WAITCNT+=1
    timeout /T %TIME_OUT% /NOBREAK
    findstr /I /C:"<Running>" "%HOME_1%\%LOG_FILE%"
    if %ERRORLEVEL% equ 0 (
        goto :LOG
    ) else (
        goto :WAIT_1
    )

:LOG
if "%JDA_LOG_FILE%"=="" GOTO :WWF_1
set /A WAITCNT=0
:WAIT_2
    set /A WAIT_TIME=ADMIN_TIME/TIME_OUT
    if %WAITCNT% gtr %WAIT_TIME% goto :PROBLEM
    set /A WAITCNT+=1
    timeout /T %TIME_OUT% /NOBREAK
    findstr /I /C:"<Running>" "%HOME_1%\%LOG_FILE%"
    if %ERRORLEVEL% equ 0 (
        goto :END
    ) else (
        goto :WAIT_2
    )

语法问题:

  • if / else结构错误;括号不平衡,并且else必须与第一个条件命令后的右括号放在同一行,如上所示,或单行显示,例如:if %ERRORLEVEL% equ 0 (goto :LOG) else (goto :WAIT_1);在这种单行方法中,else之后的命令括号是可选的,但是之前的括号是必需的;
  • 正如Stephanhis answer中指出的那样,由于引号,%ERRORLEVEL%不能等于"0";因为我们在这里比较整数值,所以我建议取消双引号并使用运算符equ而不是==;
  • 用于检查%JDA_LOG_FILE%的比较运算符为=,尽管它应为==;引号是错误的,%ERRORLEVEL%也是错误的,尽管这次,在比较字符串时,需要在两边都加上引号;如果%JDA_LOG_FILE%为空并且周围没有引号,则会引发语法错误;
  • 这不是错误,但仍然:set /A支持+=运算符,可以轻松地增加变量;您也不需要%中的变量周围的set /A符号;
  • 我建议引用findstr的文件名参数,以免出现空格时出现错误;
  • 我不确定您实际上想通过findstr查找什么:
    • 是否区分大小写的文字字符串<Running>
      如果是,请使用:findstr /I /C:"<Running>" "%HOME_1%\%LOG_FILE%";
    • 您要不区分大小写地找到单词 Running,所以要使用单词边界吗?
      如果是,请使用:findstr /I "\<Running\>" "%HOME_1%\%LOG_FILE%";
    • 您要进行区分大小写的搜索吗?
      如果是,只需从上述建议中删除/I

由于有两个(几乎)相同的循环,因此可以将公共部分移动到子例程中,通过call进行调用,并提供不同的项目作为参数。为了避免在子例程中执行goto :PROBLEM,可以让子例程返回ERRORLEVEL,其状态决定是否需要执行goto命令。这是一种可能的方法:

rem // Call sub-routine and provide some arguments:
call :SUB_LOOP "<Running>" "%HOME_1%\%LOG_FILE%"
rem // Detect if `ErrorLevel` is set and go to `:PROBLEM` then:
if %ERRORLEVEL% neq 0 goto :PROBLEM

:LOG
if "%JDA_LOG_FILE%"=="" GOTO :WWF_1
rem // Call sub-routine and provide some arguments:
call :SUB_LOOP "<Running>" "%HOME_1%\%LOG_FILE%"
rem // Detect if `ErrorLevel` is set and go to `:PROBLEM` then:
if %ERRORLEVEL% neq 0 goto :PROBLEM

rem // This is required to avoid the sub-routine to be executed unintentionally:
goto :EOF


:SUB_LOOP
    set /A WAITCNT=0
    :WAIT
    set /A WAIT_TIME=ADMIN_TIME/TIME_OUT
    if %WAITCNT% gtr %WAIT_TIME% (
        rem // Set `ErrorLevel` to one here:
        (call)
        goto :EOF
    )
    set /A WAITCNT+=1
    timeout /T %TIME_OUT% /NOBREAK
    findstr /I /C:"%~1" "%~2"
    if %ERRORLEVEL% neq 0 (
        goto :WAIT
    )
    rem // `ErrorLevel` is zero at this point;
    goto :EOF