Необъяснимое поведение, вызванное добавлением цикла for в другом случае функции при попытке исправить проблему вложенного отложенного расширения - PullRequest
0 голосов
/ 26 октября 2018

Предисловие

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

Я проверял скобки несколько раз и не могу найти ничего несбалансированного в них в полном коде внизу. С точки зрения выполнения программы это не имеет смысла, добавление цикла for влияет на операторы перед циклом for. Единственное, о чем я могу думать, это то, что происходит странная ошибка, когда код просто не выполняет полный цикл и достигает моего оператора pause сразу после цикла.

Что я на самом деле пытаюсь сделать

Я пытаюсь разграничить строку на одну строку; с неизвестным / переменным числом токенов и другими возможными разделителями в строке (например, запятыми), которые я хочу разделить ПОЗЖЕ. Этого нельзя сделать с помощью циклов for, которые были подготовлены пакетным способом, FOR / F может одновременно выполнять только строки и / или устанавливать количество токенов, а также регулярные значения для разделителей цикла с помощью точек с запятой и запятых. Я хочу разделить ПЕРВЫЙ точкой с запятой, а затем запятыми позже по отдельности. Для этого я пытаюсь сделать свой собственный простой разделитель строки для цикла с метками. Я столкнулся с проблемой, связанной с отложенным расширением моих переменных. Пример здесь:

Не полный код, но код до проблемы с отложенным расширением

setlocal EnableDelayedExpansion
set "TestArgument=%~1"
set /a "CurrentIndex=0"
set /a "DelimIndex=0"
set /a "LoopCount=0"
:ForEach
IF "!TestArgument:~%CurrentIndex%,1!"=="" (goto :ForEachEnd & echo End of list)
echo testing semicolon
IF NOT "!TestArgument:~%CurrentIndex%,1!"==";" (SET /a CurrentIndex=%CurrentIndex%+1 & goto :ForEach & echo found non ;) ELSE (
    set /a "LengthToSearch=%CurrentIndex%-%DelimIndex%"
    SET "currentArg=!TestArgument:~%DelimIndex%,!LengthToSearch!!

Что я хочу от этой конкретной части функции

Пример ввода:

set "ICMPv4RuleTest="Enable Echo Ping Request ICMPv4;Protocol,ICMPv4;Enabled,Yes;LocalIP,Any;RemoteIP,Any;Direction,In;Action,Allow""

Пример желаемых выходных данных: цикл For (метки выше), где каждая итерация принимает одну строку, разделенную; поэтому первая итерация будет принимать значение Enable Echo Ping Request ICMPv4. Весь смысл вышеизложенного состоит в том, чтобы взять входные данные и подстроку таким образом, чтобы каждая итерация была разделена точкой с запятой

Приведенный выше код, в частности, последняя строка, вызывает проблему, потому что (я думаю) программа считывает это как увеличение задержки !TestArgument:~%DelimIndex%,! (что приведет к ошибке)! (что ничто), оставляя только LengthToSearch в виде необработанной строки. Я хочу, чтобы значение LengthToSearch было раскрыто перед операцией подстроки, затем разверните / запустите / выполните расширение операции подстроки и установите для нее значение CurrentArg (строка из одной строки, разделенная символом;). Я не могу использовать знаки% с LengthtoSearch, так как он, похоже, находится в той же области действия, что и операция подстроки, однако я могу использовать знаки% с DelimIndex (потому что это выходит за рамки? Я не знаю).

Что я пробовал

Я пробовал варианты строки подстроки (последняя строка), включая:

  • SET "currentArg=!TestArgument:~%DelimIndex%,%LengthToSearch%! ничего не печатает.
  • SET "currentArg=!TestArgument:~%DelimIndex%,!!LengthToSearch!!! печатает 31 (буквальный аргумент DelimIndex).
  • SET "currentArg=%TestArgument:~%DelimIndex%,!!LengthToSearch!!% ничего не печатает.
  • SET "currentArg=%TestArgument:~%DelimIndex%,!LengthToSearch!% ничего не печатает.

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

  • SET "currentArg=!TestArgument:~%DelimIndex%,!LengthToSearch!!.

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

setlocal EnableDelayedExpansion
set "TestArgument=%~1"
set /a "CurrentIndex=0"
set /a "DelimIndex=0"
set /a "LoopCount=0"
:ForEach
IF "!TestArgument:~%CurrentIndex%,1!"=="" (goto :ForEachEnd & echo End of list)
echo testing semicolon
IF NOT "!TestArgument:~%CurrentIndex%,1!"==";" (SET /a CurrentIndex=%CurrentIndex%+1 & goto :ForEach & echo found non ;) ELSE (
    set /a "LengthToSearch=%CurrentIndex%-%DelimIndex%"
    FOR /F "tokens=*" %%A IN ("!LengthToSearch!") DO (SET "currentArg=!TestArgument:~%DelimIndex%,%%A!)

И вот, когда все стало действительно странным. По какой-то причине добавление forloop приводит к тому, что весь случай ELSE не выполняется. Когда я запускаю свой код,

IF NOT "!TestArgument:~%CurrentIndex%,1!"==";"

Только «запускается» один раз (он на самом деле не запускает все, что должен), и тогда цикл буквально прерывается. Я не имею в виду, что он подходит к концу цикла, он просто полностью игнорирует всю остальную функцию. Я проверял скобки несколько раз в полном коде ЗДЕСЬ:

Полный код функции

:FirewallRuleTestFunc
echo got to function
setlocal EnableDelayedExpansion
set "TestArgument=%~1"
ECHO PARAM WAS "%~1"
echo TestArgument was "%TestArgument%"
set /a "CurrentIndex=0"
set /a "DelimIndex=0"
set /a "LoopCount=0"
echo trying foreach
:ForEach
echo got to foreach
IF "!TestArgument:~%CurrentIndex%,1!"=="" (goto :ForEachEnd & echo End of list)
echo testing semicolon
IF NOT "!TestArgument:~%CurrentIndex%,1!"==";" (SET /a CurrentIndex=%CurrentIndex%+1 & goto :ForEach & echo found non ;) ELSE (
    echo WHY IS THIS NOT BEING REACHED.
    echo CurrentIndex is %CurrentIndex%
    echo startposition was first: %DelimIndex%
    set /a "LengthToSearch=%CurrentIndex%-%DelimIndex%"
    echo length to search was: !LengthToSearch!
    echo length to search was: %LengthToSearch%
    echo startposition was: %DelimIndex%
    FOR /F "tokens=*" %%A IN ("!LengthToSearch!") DO (SET "currentArg=!TestArgument:~%DelimIndex%,%%A!)
    echo loop of ; Arg was: !currentArg!
    set /a DelimIndex=!CurrentIndex!  
    echo Delim index was: %DelimIndex%
    IF !LoopCount! NEQ 0 (
        echo afterfirstloop
        FOR /F "tokens=1,2 delims=," %%A IN ('netsh advfirewall firewall show rule name^="!RuleName!" ^| FIND "%%A"') DO (
            echo loop of , A was '%%A'
            SET "FoundArgument=%%B"
            SET "FirewallRuleExists=%%A"
            IF "!FirewallRuleExists!"=="" (echo TEST FAILED firewall rule with name "!RuleName!" NOT FOUND)
            IF "!FoundArgument!"=="Yes" (echo Test Passed) ELSE (echo Test Failed was "!FoundArgument!")
        )
    ) ELSE (SET "RuleName=!currentArg!" & set /a "LoopCount=%LoopCount%+1" & echo firstloop done)
    echo got past if else
)
:ForEachEnd
echo end of THING
endlocal
echo SOMETHING
goto:EOF

И никакого эха ни в случае ELSE второго IF (IF NOT "!TestArgument:~%CurrentIndex%,1!"==";"), ни в любом другом эхо, кроме тех, что были до второго IF, вообще не было. Это абсолютно бессмысленно для меня, и я не могу понять, почему он игнорирует поток программы, когда добавляется цикл for, и поток программы работает, когда цикл for закомментирован. Все, что я хочу сделать, это иметь цикл for, который повторяется один раз для каждого разделителя, который я могу указать. Мое единственное предположение, что произошла какая-то ошибка, заставляющая его перейти непосредственно к EOF. сразу после вызова моей функции наступает пауза, потому что остальная часть моей программы не имеет значения. И я сейчас работаю только над этой частью. Входные данные для функции указаны ниже:

Пример вызова функции:

set "ICMPv4RuleTest="Enable Echo Ping Request ICMPv4;Protocol,ICMPv4;Enabled,Yes;LocalIP,Any;RemoteIP,Any;Direction,In;Action,Allow""
call :FirewallRuleTestFunc %ICMPv4RuleTest%

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

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

Если вы хотите разбить строку на точку с запятой , вы можете использовать этот простой метод:

@echo off
setlocal

set "ICMPv4RuleTest=Enable Echo Ping RequestICMPv4;Protocol,ICMPv4;Enabled,Yes;LocalIP,Any;RemoteIP,Any;Direction,In;Action,Allow"

echo Original string: "%ICMPv4RuleTest%"
echo/

echo Split string at semicolons:
for %%a in ("%ICMPv4RuleTest:;=" "%") do echo %%a

Выход:

Original string: "Enable Echo Ping Request ICMPv4;Protocol,ICMPv4;Enabled,Yes;Lo
calIP,Any;RemoteIP,Any;Direction,In;Action,Allow"

Split string at semicolons:
"Enable Echo Ping Request ICMPv4"
"Protocol,ICMPv4"
"Enabled,Yes"
"LocalIP,Any"
"RemoteIP,Any"
"Direction,In"
"Action,Allow"

Я видел, что вам нравится проводить несколько тестов и экспериментов, поэтому я оставляю вам объяснение этого простого метода ... ;)

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

0 голосов
/ 26 октября 2018

Что не так

УЖЕ Я обнаружил проблему.У меня была / была опечатка в моем операторе цикла FOR.Строка:

FOR /F "tokens=*" %%A IN ("!LengthToSearch!") DO (SET "currentArg=!TestArgument:~%DelimIndex%,%%A!)

В моем файле, который вызывал проблемы, были несбалансированные кавычки ("") в вызове SET.Таким образом, это вызвало сбой программы, не выполняя остальную часть функции, и вызвало у меня большую путаницу.Я нашел это, попробовав это

FOR /F "tokens=*" %%A IN ("!LengthToSearch!") DO (echo %%A)

, и поток программы ВОЛШЕБНО работал, как и ожидалось.Затем я повторно исследовал цикл for и обнаружил недостающую цитату.

а как насчет вложенных переменных с отложенным расширением?

Предложенная методология цикла for (где-то, что нельзя переопределить через google) действительно решила проблему с вложенным отложенным расширением.Я не знаю, насколько глубоко вы можете вкладывать переменные.но независимо, делая:

FOR /F "tokens=*" %%A IN ("!LengthToSearch!") DO (SET "currentArg=!TestArgument:~%DelimIndex%,%%A!)

вместо:

SET "currentArg=!TestArgument:~%DelimIndex%,!LengthToSearch!!

На самом деле работает как ожидалось!Он разделяет строку с правильными вложенными значениями индексации.Я не могу вспомнить, где это было упомянуто, но я вспоминаю объяснение как это: расширение цикла FOR происходит до отложенного расширения переменной, но после начального расширения знаков%.Таким образом, я могу поместить аргументы цикла for в отложенную операцию расширения, и она будет работать.Я не знаю, почему именно это работает, но вот как я это понимаю.Я был бы признателен за любую дополнительную информацию, и я отредактирую этот ответ, если узнаю больше информации о том, почему эта проблема возникает и как я только что решил ее.

Просто для протокола, я НЕНАВИЖУ такие ошибки.Я действительно хотел бы, чтобы была лучшая обработка ошибок, потому что пакетный сценарий является мощным, но излишне сложным, потому что нет хорошей проверки ошибок.Если бы только notepad ++ показывал несбалансированные кавычки в переменных.Но для дальнейшего использования, по крайней мере, это решает любые проблемы с попыткой использовать вложенные переменные отложенного расширения.Решение состоит в том, чтобы просто использовать переменные цикла в качестве посредника.

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

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