4

У меня странное поведение при установке уровня ошибки в пакетном скрипте на 0.

Я вызываю пакетный скрипт a.bat для задания Jenkins, которое, в свою очередь, вызывает второй скрипт b.cmd и оценивает уровень ошибки после вызова:

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

"Основной" скрипт:

:: 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

(Я позаимствовал материал :seterr из этого вопроса)

Что происходит, когда я запускаю работу Дженкинса:

  1. md возвращается и Равен 1, поскольку каталог уже существует.
  2. вызов :seterr не имеет ожидаемого эффекта, уровень ошибки остается 1
  3. вызов b.cmd завершается без проблем, уровень ошибки в b равен 0, но после вызова уровень ошибки в a по- прежнему равен 1, чего я определенно не ожидал бы после прочтения ответов на связанный вопрос.
  4. после перехода к :error и вызову popd , errorlevel внезапно сбрасывается в 0 - чего я тоже не ожидал.

Кто-нибудь знает, что здесь происходит? Я случайно не установил уровень ошибки вручную, поэтому это должна быть системная переменная, а не пользовательская.

2 ответа2

7

Вы не показали весь сценарий. Единственное возможное объяснение, о котором я знаю, это то, что ваш код находится внутри большего блока кода, заключенного в скобки, возможно, является частью цикла FOR или условия IF.

% ERRORLEVEL% раскрывается при разборе строки и разборе всего блока в скобках одновременно. Таким образом, ОШИБКА, которую вы видите, должна была существовать до начала внешнего паратеза.

Вы должны использовать отложенное расширение, если хотите увидеть изменяющееся значение в блоке кода.

Вот простая демонстрация:

@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!
)

-- ВЫХОД --

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

Хотя этот запрос разрешен, существует еще одна причина для поведения, подобного описанному. Например, поместите это в командный файл и запустите:

@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.

Если вы наблюдаете вывод этой партии, строка, начинающаяся с 3: будет отсутствовать, а строка, начинающаяся с 4: будет вредной.

Вывод: не оценивать уровень ошибки с помощью% errorlevel%, а с if errorlevel.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .