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


4

Eu tenho um comportamento estranho, definindo o nível de erro em um script em lotes para 0.

Estou chamando um script a.batem lote em um trabalho Jenkins, que por sua vez chama um segundo script b.cmde 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 :seterrmaterial desta pergunta )

O que parece acontecer quando executo o trabalho de Jenkins:

  1. md retorna e nível de erro está definido como 1, porque o diretório já existe.
  2. a chamada para :seterrnão tem o efeito esperado, o nível de erro permanece 1
  3. a chamada para b.cmdtermina sem problemas, o nível de erro bé 0, mas após a chamada o nível de erro aindaa é 1, o que eu definitivamente não esperaria depois de ler as respostas da pergunta vinculada.
  4. após o salto :errore a chamada de popd, errorlevel repentinamente é redefinido para 0 - o que eu também não esperaria.

Alguém tem idéia do que pode estar acontecendo aqui? Não defini acidentalmente o nível de erro manualmente, por isso deve ser a variável do sistema, não definida pelo usuário.


Você está trabalhando com setlocal / endlocal em algum lugar?
Marsh-wiggle

@boboes não setlocal / endlocal em nenhum dos scripts.
Arne Mertz

Respostas:


7

Você não mostrou o script inteiro. A única explicação possível de que tenho conhecimento é que seu código está dentro de um bloco de código entre parênteses maior, possivelmente parte de um loop FOR ou de 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 parêntese mais externa.

Você deve usar a expansão atrasada se desejar ver um valor alterado 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!
)

-- RESULTADO --

Normal expansion shows value before block started: BEFORE
Delayed expansion shows the current value: AFTER

Obrigado. Você está certo, eu não lhe mostrei as ~ 120 linhas inteiras. Vou procurar blocos de código entre parênteses assim que voltar ao trabalho.
Arne Mertz

Era de fato um bloco if, eu editei a questão (a partida se-bloco após o :: (!)comentário Thansk para esclarecer o meu erro.!
Arne Mertz

0

Embora essa solicitação seja resolvida, há outro motivo para um comportamento como o descrito. Por exemplo, coloque isso em um arquivo em lotes 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 deste lote, a linha que começa com 3: estará faltando e a linha que começará com 4: será prejudicial.

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


11
Você pula para a conclusão errada. Há momentos em que o valor exato de ERRORLEVEL é necessário; nesse caso, %ERRORLEVEL%é a única opção razoável. A conclusão correta é que você nunca deve definir sua própria variável de ambiente ERRORLEVEL, pois ela substitui o valor dinâmico. O mesmo é verdadeiro para as outras variáveis dinâmicas, como pseudo %CD%, %TIME%, %DATE%, %RANDOM%, etc. Se a variável é definida, em seguida, o comportamento dinâmico é restaurada por retirar definição da variável comset "errorlevel="
dbenham
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.