Пакетная обработка исключений с использованием цикла FOR с многострочным IN, в котором выполняются команды TRYed.Является ли это возможным? - PullRequest
0 голосов
/ 06 декабря 2018

Что я делаю

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

Как я пытаюсь это сделать

Я пытался реализовать то, что яМы назовем «try catch бедного человека», который на самом деле является просто циклом FOR, который запускает пакетные команды построчно, и если errorlevel выше 0, строка перехватывается циклом в IF изDO пункт.Например, я попытался написать это в пакетном режиме:

@echo OFF
SET /A "LineCount=1"
FOR /F "tokens=* delims=" %%A IN ('SET "VarATest^=something" ^^ SET "VarBTest^=somethingelse" ^^ SE "VarCTest^=syntaxerror"') DO (SET /A "LineCount=1+!LineCount!" & IF !ERRORLEVEL! EQU 1 (echo errorlevel was: "!ERRORLEVEL!" and line was "!LineCount!") ELSE (echo line worked))
pause 

В основном то, что предполагается сделать выше, это инициализировать переменную LineCount, запустить три пакетных команды в предложении IN (разделенныхстрока ^ заканчивается), и для каждой строки увеличьте значение LineCount и проверьте, не вызвало ли строка errorlevel чего-либо большего, чем 1 (!ERRORLEVEL! EQU 1 имеет такое странное поведение).Третья строка имеет очевидную синтаксическую ошибку: SET пишется SE, что должно вызывать errorlevel выше 0. Смысл в демонстрации, это можно было бы уточнить, но сейчас это просто для подтверждения концепции.

проблема

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

A.Можно ли запускать пакетные команды построчно в предложении IN цикла FOR, чтобы имитировать попытку try?Очевидно, это означает более частое использование отложенного расширения и escape-символов, но было бы здорово иметь эту элементарную функциональность.

B.Если это возможно, то как правильно сделать так, чтобы ввод условия IN был неформатированным текстом, но в то же время многострочным.Например, предложение IN прямо сейчас:

(SET "VarATest^=something" ^^ SET "VarBTest^=somethingelse" ^^ SE "VarCTest^=syntaxerror")

, которое я хочу, чтобы функционально было похоже на обычный код пакета:

SET "VarATest=something"
SET "VarBTest=somethingelse"
SE "VarCTest=syntaxerror"

Где третья строка явно вызываетошибка.Я не хочу использовать другой файл, если это возможно, поэтому нет временных файлов, содержащих код блока try.Буду ли я использовать ^ конец строки?Я попытался ^^, думая, что мне нужно выйти из первой строки.Я также пробовал переводы строк, где были ^^, но это тоже не работало.Я попытался изменить разделители, чтобы попытаться разделить команды таким образом, может быть, запускать их каждый таким образом, но все равно я не получаю вывод.полезно, но, к сожалению, не принесло решения, однако после того, как я поработал, я придумал следующее:

@echo OFF && setlocal enableextensions enabledelayedexpansion 

SET lf=^&echo/^^



SET /A "LineCount=0"
FOR /F "tokens=*" %%A IN ('call!lf!SET "VarATest^=something"!lf!SET "VarBTest^=somethingelse"!lf!SET "VarCTest^=syntaxerror"!lf!') DO (SET /A "LineCount=1+!LineCount!" && echo ER: "!ERRORLEVEL!" or "%ERRORLEVEL%" A: "%%A" && IF !ERRORLEVEL! NEQ 0 (echo errorlevel was: "!ERRORLEVEL!" and line was "!LineCount!") ELSE (echo line worked = !LineCount!))
pause >nul 
echo/!LineCount! && pause >nul 

Теперь это в основном ответ с несколькими оговорками.Добавление в часть "tokens=*" фактически дает полную строку SET.Ответ предоставлен механизм перевода строки.Экспериментально я заметил, что call!lf! был необходим ДО первой команды в «строке».Я понятия не имею, почему, но это не работает по-другому, потому что цикл FOR, похоже, хочет пропустить первый аргумент.Я получил распечатку каждой командной строки в строке через %% A.фантастика!Единственная проблема заключается в том, что ошибки не обнаруживаются, когда они должны быть.ERRORLEVEL не меняется, когда я изменяю последнюю командную строку с

SET "VarCTest^=syntaxerror"

на:

ST "VarCTest^=syntaxerror"

или любые другие подобные варианты, которые могут вызвать ошибку.Проблема в том, что команды SET никогда не выполняются.Эхо их после цикла FOR показывает это.Я собираюсь попытаться заставить их работать

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Итак, я наконец-то получил код к этому моменту.Это заняло массу экспериментов и небольшие проблемы с выходом из двойных кавычек и сбросом уровня ошибки, но код, который я получил, работал так:

@echo OFF && setlocal enableextensions enabledelayedexpansion 

SET lf=^&echo/^^



SET /A "LineCount=0"
FOR /F "tokens=* delims=" %%A IN ('call!lf!ST ""VarATest^=something""!lf!SET ""VarBTest^=somethingelse""!lf!SET ""VarCTest^=syntaxerror""!lf!') DO (SET /A "LineCount=1+!LineCount!" && call :RunMyCommandSubroutine "%%A")
echo A: "!VarATest!"
echo A: "%VarATest%"
echo B: "!VarBTest!"
echo B: "%VarBTest%"
echo C: "!VarCTest!"
echo C: "%VarCTest%"
pause >nul
goto:EOF

:catchsubroutine
echo [43;97mError on "!LineCount!" Error code !ERRORLEVEL![0m 
goto:EOF

:RunMyCommandSubroutine
SET "StringImUsing=%~1"
SET "StringImUsing=%StringImUsing:""="%"
%StringImUsing% >nul 2>&1
IF !ERRORLEVEL! NEQ 0 (echo [43;97mLine was %StringImUsing%[0m && call :catchsubroutine) ELSE (echo line worked = !LineCount!)
(call )
goto:EOF

как я это сделал

Итакчтобы проверить это, вы можете создать опечатку в командных строках SET в части IN цикла for и увидеть, что эта конкретная «строка» помечена желтым цветом как ошибка (например, попробуйте сделать SET в ST).Возможно, вам всем интересно, для чего предназначен (call ) в подпрограмме RunMyCommand.Это для сброса ERRORLEVEL в 0, но не навсегда.Я упал из-за ошибки SET самого errorlevel (используя SET /A "ERRORLEVEL=0"), который создает копию и не использует системную переменную errorlevel, которую я заметил, так как она осталась 0 после того, как я «сбросил» еедаже когда произошла ошибка.Так что после исправления этого и избежания двойных кавычек вокруг аргумента SET с помощью "" мне также нужно было создать подпрограмму, потому что установка проверки для errorlevel в DO IF приводила к тому, что проверка была равна единице.слишком поздно, потому что когда цикл FOR получает ошибку в предложении DO, кажется, что он останавливает все остальное и переходит к следующему аргументу.Я также понял, что вы можете просто использовать командную строку для «запуска» команды (например, если у меня есть команда в %%A, просто наберите %%A в отдельной строке, и команда будет работать нормально).Итак, у нас есть правильная проверка, правильный errorlevel сброс, правильный способ запуска наших многострочных входных строк, и я даже вставил несколько кодов ANSI, чтобы интерфейс выглядел красиво.

Справочник по будущему

В целом довольно круто!Я понятия не имею, может ли это работать с более сложными примерами, такими как вложенные IF s FOR s или другими странными командами, но он должен проверять наличие любой ошибки, которая приводит к тому, что errorlevel будет отличным от нуля.У меня также есть подпрограмма catch, которая позволяет выполнять очистку практически сразу после запуска строки с ошибками.Это позволяет выполнять некоторые операции очистки.Так эй!Оказывается, это было (Сорта) возможно!

Все еще большое благодаря Kapputz.Его ответ не был решением, но он помог ALOT со многими разными вещами, которые мне нужно было понять.

0 голосов
/ 06 декабря 2018

Это не совсем ответ на этот вопрос, но он слишком велик, чтобы поместиться в комментарии ...

  • Для запуска нескольких команд в командном файле, который выдолжен разделять их символом & (или его вариантами).Это очень простая точка пакетного файла.
  • Символ ^ - это , а не"конец строки" (где вы это прочитали?).Он используется для экранирования следующего символа.Когда следующий символ является концом текущей строки, тогда текущая строка «переходит» в следующую (с некоторыми ограничениями).
  • Поведение команды for /F запускает все команды, помещенные в IN сначала предложение и, после окончания последней команды , начинайте итерацию команд, помещенных в for-body, используя строки, сгенерированные в IN part.
  • Метод, который for /F использует для выполнения команд в IN предложение через дочерний cmd.exe процесс.Невозможно напрямую передать любое значение уровня ошибки из этого cmd.exe командам, помещенным в for-body, за исключением текстового файла.
  • Дочерний элемент cmd.exe выполняетсяв контексте командной строки , НЕ в контексте пакетного файла , поэтому для изменения поведения команд, размещенных в части IN, требуется специальное управление.
  • Вся эта информация уже опубликована на многих сайтах, связанных с пакетными файлами.Любой может найти и найти его, если у него / нее есть интерес ...

РЕДАКТИРОВАТЬ : я добавил код, на который предположительно отвечаетвопрос.

Я действительно не понимаю, какова цель этой темы, и я не понимаю многие (почти все) описания, которые вы используете, чтобы объяснить, что вы делаете ... Несмотря наваши обширные объяснения (с большим количеством нетехнических слов и отвлекающими "заголовками глав"), вы не четко описали, что вы хотите в качестве конечного результата, и как вы хотите, чтобы получить такой результат.По этой причине я могу только догадываться ... Итак, я думаю, вы ищете что-то похожее на это:

@echo off
setlocal EnableDelayedExpansion

SET /A "LineCount=0"
FOR %%A IN ( "SET ""VarATest=something"""
             "ST  ""VarBTest=syntaxerror"""
             "SET ""VarCTest=somethingelse""" ) DO (
   SET /A "LineCount+=1"
   SET "StringImUsing=%%~A"
   SET "StringImUsing=!StringImUsing:""="!"
   !StringImUsing! >nul 2>&1

   IF !ERRORLEVEL! NEQ 0 (
      echo Line was !StringImUsing!
      echo Error on "!LineCount!" Error code !ERRORLEVEL!
      VER >nul
   ) ELSE (
      echo line worked = !LineCount!
   )

)

echo A: "%VarATest%"
echo B: "%VarBTest%"
echo C: "%VarCTest%"

VER - это команда, используемая для сброса ERRORLEVEL в ноль, как описано ниже Таблица 4 на этот ответ .Это намного более простая и стандартная команда, чем странный (call ) трюк ...

0 голосов
/ 06 декабря 2018

Если я правильно понял ваш вопрос:

enter image description here

@echo off & setlocal EnableDelayedExpansion & color 0a
for /f %%a in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo 0x1B"') do set "Esc=%%a"
SET lf=^&echo/^^

SET /A "LineCount=1"
FOR /F %%A IN ('SET /p "VarATest=something"^<nul!lf!SET /p "VarBTest=somethingelse"^<nul!lf!SET /p "VarCTest=syntaxerror"^<nul!lf!') DO (
    SET /A "LineCount=1+!LineCount!"
    IF "!ERRORLEVEL!" == "1" (
        echo errorlevel was: "!ERRORLEVEL!" and line was "!LineCount!"
    ) ELSE (
        echo line worked = !LineCount!
    )
    echo/!Esc![4m!Esc![31mError on "!LineCount!" Error code !ERRORLEVEL!!Esc![0m 
)

pause >nul 
echo/!LineCount! & pause >nul 

Примечание: После SET lf=^&echo/^^, 2 строкиниже необходимо сделать «фальшивую линию разрыва».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...