Обработка сообщений об ошибках с файлами запускается автоматически с помощью пакетного сценария

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

Во-первых, я хотел бы добавить скрипт, который сделает запись нулевой, когда появится сообщение об ошибке.

У меня есть цикл, который выглядит так

for /f "delims=_" %%J IN ('forfiles /p "%%F" /m *.ext/c "cmd /c echo @path"')  DO (
    set start=!time!
    start "PROGRAM"  /D "c:\Path\to\the\PROGRAM" /Wait program -r  %%J  

    rem This loop uses a regular expression to find the database name from the .ext file
    rem and sets it to a variable.
    for /f "tokens=3 delims=<>" %%a in  ('findstr "<Name>ABCDir" "%%~fJ"') do set name=%%a

set end=!time!

rem The following two loops convert start time and end time to centiseconds.
rem The time variable will be converted to minutes inside a sql query so that floats are possible.
for /F "tokens=1-4 delims=:.," %%a in ("!start!") do (
        set /a "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
    )       

for /F "tokens=1-4 delims=:.," %%a in ("!end!") do (
        set /a "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
    )

rem Calculate the elapsed time by subtracting values
set /A elapsed=end-start

sqlcmd -S SERVER -d DATABASE -v Var1 = "!name!" Var2 = "%variable2%" Var3 = !elapsed! Var4 = %variable4% -i "\\path\to\the\query\Insert.sql"
)

Поэтому я хотел бы, чтобы каждый раз, когда появляется сообщение об ошибке, скрипт запускал следующий файл и менял переменную !elapsed! на null.

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

@ECHO OFF
IF ERRORLEVEL 1 SET ERRORLEV=1
IF ERRORLEVEL 2 SET ERRORLEV=2
IF ERRORLEVEL 3 SET ERRORLEV=3
IF ERRORLEVEL 4 SET ERRORLEV=4
   •
   •
   •
IF ERRORLEVEL 254 SET ERRORLEV=254
IF ERRORLEVEL 255 SET ERRORLEV=255
ECHO ERRORLEVEL = %ERRORLEV%

но кажется, что должен быть более эффективный способ сделать это, например, с циклом, который подсчитывает уровень ошибки, я устанавливаю errorlev = i, где i = 0, и переходит к n.

Я очень ценю любое понимание, которое вы, ребята, можете предложить.


person David    schedule 21.01.2015    source источник
comment
будет ли эта работа помещена внутри цикла? set /A elapsed=end-start echo Elapsed Time: !elapsed! IF !ERRORLEVEL! GTR 0 echo Error Level !ERRORLEVEL! Occurred. IF !ERRORLEVEL! GTR 0 set elapsed=NULL   -  person David    schedule 21.01.2015


Ответы (1)


Во-первых, если все, что вы хотите сделать, это условное выполнение, основанное на нулевом или ненулевом коде выхода "PROGRAM", используйте && и || для обозначения блоков кода для успешного или неудачного выполнения, как показано ниже:

for /f "delims=_" %%J IN ('forfiles /p "%%F" /m *.ext/c "cmd /c echo @path"')  DO (
    set start=!time!
    start "PROGRAM"  /D "c:\Path\to\the\PROGRAM" /Wait program -r  %%J && (

        rem program exited status 0 (success)

        rem This loop uses a regular expression to find the database name from the .ext file
        rem and sets it to a variable.
        for /f "tokens=3 delims=<>" %%a in  ('findstr "<Name>ABCDir" "%%~fJ"') do set name=%%a

        set end=!time!

        rem The following two loops convert start time and end time to centiseconds.
        rem The time variable will be converted to minutes inside a sql query so that floats are possible.
        for /F "tokens=1-4 delims=:.," %%a in ("!start!") do (
            set /a "start=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
        )       

        for /F "tokens=1-4 delims=:.," %%a in ("!end!") do (
            set /a "end=(((%%a*60)+1%%b %% 100)*60+1%%c %% 100)*100+1%%d %% 100"
        )

        rem Calculate the elapsed time by subtracting values
        set /A elapsed=end-start

        sqlcmd -S SERVER -d DATABASE -v Var1 = "!name!" Var2 = "%variable2%" Var3 = !elapsed! Var4 = %variable4% -i "\\path\to\the\query\Insert.sql"

    ) || (

        rem Program exited status non-zero (fail)
        set "elapsed="
        rem Continue looping to next result of forfiles

    )
)

См. эту страницу, чтобы узнать больше об этом виде условного выполнения.

Что касается повторения уровня ошибки, то он уже находится в %ERRORLEVEL%. Вам не нужно использовать серию операторов if ERRORLEVEL, чтобы установить его. Попробуйте это в командной строке:

cmd /c exit /b 5
echo %ERRORLEVEL%

Должно быть эхо 5.

Еще одно замечание, хотя я не уверен, что вам это все еще нужно, зная то, что вы знаете сейчас, if ERRORLEVEL N проверяет, больше ли %ERRORLEVEL% или равно N. Таким образом, if ERRORLEVEL 5 вернет true, если %ERRORLEVEL% равно 8. По этой причине серия if ERRORLEVEL команд обычно пишут в порядке убывания.

if ERRORLEVEL 3 (
    do stuff
) else if ERRORLEVEL 2 (
    do something else
) else etc...
person rojo    schedule 21.01.2015
comment
Хорошо, прочитав об условном выполнении, я убежден, что это лучший способ, но я просто не следую логике. Можете ли вы логически объяснить, почему вы поставили && и || именно там, где вы это сделали? - person David; 22.01.2015
comment
о, и просто чтобы убедиться, что я следую второй части, мне просто нужно добавить echo %ERRORLEVEL% в мой скрипт, потому что уровень ошибки всегда хранится в этой переменной? Я использую enabledelayedexpansion в своем сценарии для переменных, установленных в цикле, должен ли я использовать !ERRORLEVEL! вместо %ERRORLEVEL%? - person David; 22.01.2015
comment
Он оценивается как expression && success || fail. Я думаю более конкретно, (expression && (success code block)) || (fail code block), поэтому неудача не предшествует успеху. В противном случае && success всегда было бы истинным. Этот синтаксис обычно используется для проверки существования строки в другой строке, например ping -n 1 host | find "TTL=" >NUL && success || fail. В этом примере find устанавливает уровень ошибки 0, если найден, и 1, если не найден. Re: вторая часть, да, просто добавьте echo Program exited with status code %ERRORLEVEL% везде, где вы хотите, чтобы это повторялось. - person rojo; 22.01.2015
comment
@David Если мой ответ был полезен, отметьте его как принятый. см. эту страницу, чтобы узнать, почему это важно. - person rojo; 22.01.2015
comment
Прошу прощения, что не ответил, другие дела на работе отвлекли меня от этой задачи на несколько дней. Я не уверен, что условное выполнение - это то, что я ищу. Я не хочу, чтобы программа выполнялась или не выполнялась в зависимости от того, успешно прошла последняя итерация или нет. Я хочу иметь строку, чтобы при появлении кода ошибки она меняла значение переменной на null. - person David; 23.01.2015
comment
Так что просто пропустите часть && ( code block ) и сделайте start program etc. || set "elapsed=". Позже вы можете проверить, был ли start program неудачным с if not defined elapsed, если хотите. Если вы предпочитаете, вы можете start program etc в одной строке, затем в следующей строке if errorlevel 1 set "elapsed=". Это 6 одного, полдюжины другого, на самом деле. Оба стиля выполняют идентичные действия. - person rojo; 23.01.2015
comment
Спасибо!, я попробую это. - person David; 23.01.2015
comment
Я не могу заставить это работать в моем коде. Я настроил код так, чтобы он выглядел так && (file loop) || (error loop), но каждый раз, когда я выполняю код, происходит сбой. Я реализовал это так же, как вы сделали в своем ответе. - person David; 27.01.2015
comment
Ваш псевдокод в порядке. Попробуйте отключить @echo off и посмотрите, сможете ли вы увидеть, какая команда вызывает сбой. Если это не поможет, обновите свой вопрос обновленным кодом или опубликуйте новый вопрос. - person rojo; 28.01.2015
comment
Комментарии актуальны? Я просматривал страницу, на которую вы ссылались, объясняя это, и, похоже, это так. - person David; 28.01.2015
comment
Какие комментарии уместны где? Вы имеете в виду rem утверждения в сценарии в моем ответе? Большинство из них ваши. Вы спрашиваете, влияют ли они на оценку сценария? Нет, я так не думаю. Я думаю, вы должны опубликовать новый вопрос. - person rojo; 28.01.2015
comment
Я имел в виду комментарии, которые вы добавили - person David; 28.01.2015
comment
Вы имеете в виду rem program exited status 0 (success) и rem Program exited status non-zero (fail)? Они здесь только для того, чтобы проиллюстрировать назначение && и ||. Вы можете удалить эти и все остальные строки rem, если хотите, и это не должно повлиять на работу скрипта. - person rojo; 28.01.2015