Отсутствует терминатор в PowerShell CLI в цикле for с использованием расширенных переменных

Я хочу использовать цикл for для замены только второго совпадения строки в файле. Для этого я использую команду PowerShell CLI, которая работает вне цикла for.

Теперь, поскольку мне приходится перебирать несколько файлов, определенных в %files%, я использую for /f "tokens=1", чтобы отделить файл 1 от файла 2, поскольку обе строки, которые я хочу заменить, находятся в файле 1.

Это цикл for, который я использую:

for /l %%a in (1,1,2) do (
    for /f "tokens=1" %%b in ("!files!") do (
        set "file=%apb%\%%~b"
        echo !string[%%a]! --^> !replace[%%a]!
        rem Use PowerShell to replace only the second occurrence of a match, here `$matches[1]`.
        PowerShell -NoLogo -NoProfile -Command ^
            "$file = '!file!';" ^
            "$string = '(?m)^!string[%%a]!=.*';" ^
            "$content = Get-Content -Raw -Encoding UTF8 $file;" ^
            "$matches = [regex]::Matches($content, $string);" ^
            "if ($matches.Count -ge 2) {" ^
            "   $stringTwo = $matches[1];" ^
            "   $stringTwoPosition = $stringTwo.Index;" ^
            "   $stringTwoLength = $stringTwo.Length};" ^
            "Set-Content -NoNewLine $file -Value $content.Remove($stringTwoPosition, $stringTwoLength).Insert($stringTwoPosition, '!string[%%a]!=!string[%%a]!')"
    )
)

Моя проблема с циклом for заключается в том, что он возвращает следующую ошибку:

The string is missing the terminator: '.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

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

Я пробовал вызывать значения !string[%%a]! и !replace[%%a]! через нерасширяемые переменные %stringAlias% и %replaceAlias%, но это не сработало.

Это оставшаяся часть фрагмента для подготовки к последнему циклу for:

@echo off
setlocal EnableDelayedExpansion
rem Set target files.
set "files=Engine\Config\BaseEngine.ini APBGame\Config\DefaultEngine.ini"
rem Initialize variables.
set "replace = "
set "string = "
call :subroutine.ping_optimization "%files%"
if !errorlevel! equ 0 (
    set "count=1"
    for %%a in (
        "1.0"
        "5.0"
        rem ...
    ) do (
        set "replace[!count!]=%%~a"
        set /a "count+=1"
    )
)
if !errorlevel! equ 1 (
    set "count=1"
    for %%a in (
        "0.001"
        "0.001"
        rem ...
    ) do (
        set "replace[!count!]=%%~a"
        set /a "count+=1"
    )
)
set "count=1"
for %%a in (
    "AckTimeout"
    "KeepAliveTime"
    rem ...
) do (
    set "string[!count!]=%%~a"
    set /a "count+=1"
)
rem for loop causing issues goes here...

Отступим назад: если вам все равно нужно выполнить большую часть сценария в PowerShell, почему бы не сделать все это в PowerShell? Он имеет более разумные конструкции циклов.

Tim Roberts 18.08.2024 23:43

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

leiseg 18.08.2024 23:49

Ошибка здесь: `$matches[1]`. Это в строке примечаний. Вам не нужны обратные тики, особенно второй перед менструацией.

jdweng 19.08.2024 00:17

@jdweng Удаление обратных кавычек или `$matches[1]` в целом, к сожалению, не вызвало у меня ошибки.

leiseg 19.08.2024 00:42

@jdweng: Если бы вы попробовали свою рекомендацию, вы бы поняли, что в данном случае это не имеет никакого значения. Пожалуйста (а) удалите свой комментарий, который сбивает с толку, и (б) в будущем давайте только те советы, которые вы сами убедились в том, что они работают так, как задумано.

mklement0 19.08.2024 01:32

Если, как вы говорите, рекомендация ничего не изменила, то есть ли какой-то вред в том, что она останется @mklement0? Я просто хотел добавить, что у меня даже нет компьютера с Windows, поэтому я не проверяю ничего, что публикую, пока не получу отзыв о том, что это не работает, и я могу откуда-нибудь использовать его.

Compo 19.08.2024 04:19

@Compo, в этом еще есть вред: комментарий не имеет значения, и любой, кто последует его примеру, скорее всего, запутается и / или напрасно потратит время. Как правило, можно публиковать комментарии, основанные на четком понимании предмета: в этом случае явная проверка обычно не требуется (хотя в ситуативной ситуации совет все равно может быть неверным). Я не публикую комментарии, подобные моему предыдущему, легкомысленно, поскольку они могут быть восприняты как необоснованные аргументы ad hominem; однако в рассматриваемом случае я замечаю повсеместное распространение бесполезных комментариев от одного автора, чему я пытаюсь воспрепятствовать.

mklement0 19.08.2024 04:27

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

Compo 19.08.2024 04:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Одним из многих неудачных вариантов поведения cmd.exe (интерпретатора пакетных файлов) является то, что команды ведут себя по-разному внутри (...)-заключенных тел for /f циклов.

В частности, внутристрочный символ ^ в "$string = '(?m)^!string[%%a]!=.*';" ^ — даже если он находится внутри строки "..." — по необъяснимым причинам не используется дословно и требует экранирования как ^^.

То есть замена строки
"$string = '(?m)^!string[%%a]!=.*';" ^ в коде вашего вопроса с
"$string = '(?m)^^!string[%%a]!=.*';" ^ должен решить вашу проблему.

Другие вопросы по теме