Sair / b 0 não define% errorlevel% como 0

4

Eu tenho um comportamento estranho para definir errorlevel em um script em lote para 0.

Estou chamando um script em lote a.bat em um trabalho do Jenkins, que, por sua vez, chama um segundo script b.cmd e avalia o nível de erro após a chamada:

:: b.cmd
:: some stuff, but relevant is only this:
@echo b errorlevel: %errorlevel%
EXIT /B 0

O script "principal":

:: a.bat
pushd %CD%
cd..

@echo a errorlevel: %errorlevel%

set outputdir=".\some\exisiting\dir"
:: (1)
md %outpurdir%
@echo a errorlevel: %errorlevel%

:: (!)
if "$somevar" = "FOO" ( 
  cd .\WhereBIs

  :: (2)
  call :seterr 0
  @echo a errorlevel: %errorlevel%

  :: (3)
  call b.cmd

  @if %errorlevel% neq 0 (
    @echo a errorlevel: %errorlevel%
    set errmsg=Error calling b
    goto error
  )

  :: more stuff
)

:error
@echo %errmsg%
popd
:: (4)
@echo a errorlevel: %errorlevel%
@if %errorlevel% neq 0 exit %errorlevel%
Exit /B 1

:seterr
exit /b %1

(Eu peguei emprestado o :seterr de esta pergunta )

O que parece acontecer quando eu executo o trabalho de Jenkins:

  1. md retorna e errorlevel está definido como 1, porque o diretório já existe.
  2. a chamada para :seterr não tem o efeito esperado, o nível de erro permanece 1
  3. a chamada para b.cmd é concluída sem problemas, errorlevel em b é 0, mas após o nível de erro da chamada em a é ainda 1, o que definitivamente não esperaria depois de ler o respostas para a questão ligada.
  4. após o salto para :error e a chamada de popd , o errorlevel é repentinamente redefinido para 0 - o que eu também não esperaria.

Alguém tem alguma idéia do que pode estar acontecendo aqui? Eu não configurei acidentalmente o errorlevel manualmente, então deve ser a variável do sistema, não uma definida pelo usuário.

    
por Arne Mertz 30.12.2014 / 10:22

2 respostas

7

Você não mostrou o script inteiro. A única explicação possível de que estou ciente é que seu código está dentro de um bloco maior de código entre parênteses, possivelmente parte de um loop FOR ou uma condição IF.

% ERRORLEVEL% é expandido quando a linha é analisada e todo o bloco entre parênteses é analisado ao mesmo tempo. Portanto, o ERRORLEVEL que você está vendo deve ter existido antes do início da parantesia mais externa.

Você deve usar a expansão atrasada se quiser ver um valor de mudança dentro de um bloco de código.

Aqui está uma demonstração simples:

@echo off
setlocal enableDelayedExpansion
set var=BEFORE
(
  set var=AFTER
  echo Normal expansion shows value before block started: %var%
  echo Delayed expansion shows the current value: !var!
)

- OUTPUT -

Normal expansion shows value before block started: BEFORE
Delayed expansion shows the current value: AFTER
    
por 30.12.2014 / 22:25
0

Embora esta solicitação seja resolvida, há outro motivo para um comportamento como descrito. Exemplo, coloque isso em um arquivo de lote e execute-o:

@set errorlevel=
@dir >nul
@if %errorlevel% equ 0 (echo 1: Correctly detected: No error!) else echo.
@if not errorlevel 1 (echo A: Correctly detected: No error!) else echo.
@dir nonexistent >nul
@if %errorlevel% neq 0 (echo 2: Correctly detected: An error!) else echo.
@if errorlevel 1 (echo B: Correctly detected: An error!) else echo.

@set errorlevel=7
@dir >nul
@if %errorlevel% equ 0 (echo 3: Correctly detected: No error!) else echo.
@if not errorlevel 1 (echo C: Correctly detected: No error!) else echo.
@dir nonexistent >nul
@if %errorlevel% neq 0 (echo 4: Correctly detected: An error!) else echo.
@if errorlevel 1 (echo D: Correctly detected: An error!) else echo.

Se você observar a saída desse lote, a linha que começa com 3: estará faltando, e a linha que começa com 4: será maliciosa.

Conclusão: não avaliar o nível de erro com% errorlevel%, mas com if errorlevel.

    
por 16.02.2015 / 12:29