Я хочу использовать цикл 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...
По сравнению со всем пакетным сценарием, команды CLI PowerShell — лишь малая его часть, и я не хочу конвертировать все на другой язык, особенно если я не настолько знаком и не уверен в PowerShell. Я просто использую команды PowerShell CLI для поиска и замены текста, поскольку это кажется более эффективным.
Ошибка здесь: `$matches[1]`. Это в строке примечаний. Вам не нужны обратные тики, особенно второй перед менструацией.
@jdweng Удаление обратных кавычек или `$matches[1]`
в целом, к сожалению, не вызвало у меня ошибки.
@jdweng: Если бы вы попробовали свою рекомендацию, вы бы поняли, что в данном случае это не имеет никакого значения. Пожалуйста (а) удалите свой комментарий, который сбивает с толку, и (б) в будущем давайте только те советы, которые вы сами убедились в том, что они работают так, как задумано.
Если, как вы говорите, рекомендация ничего не изменила, то есть ли какой-то вред в том, что она останется @mklement0? Я просто хотел добавить, что у меня даже нет компьютера с Windows, поэтому я не проверяю ничего, что публикую, пока не получу отзыв о том, что это не работает, и я могу откуда-нибудь использовать его.
@Compo, в этом еще есть вред: комментарий не имеет значения, и любой, кто последует его примеру, скорее всего, запутается и / или напрасно потратит время. Как правило, можно публиковать комментарии, основанные на четком понимании предмета: в этом случае явная проверка обычно не требуется (хотя в ситуативной ситуации совет все равно может быть неверным). Я не публикую комментарии, подобные моему предыдущему, легкомысленно, поскольку они могут быть восприняты как необоснованные аргументы ad hominem; однако в рассматриваемом случае я замечаю повсеместное распространение бесполезных комментариев от одного автора, чему я пытаюсь воспрепятствовать.
Конечно, вид принятого ответа снижает вероятность того, что кто-то последует за комментарием, как если бы это был ответ. (Хотя это может сбить с толку, поскольку оно получило одобрение). Я не поддерживаю jdweng, это ваша битва, деритесь как хотите.
Одним из многих неудачных вариантов поведения cmd.exe
(интерпретатора пакетных файлов) является то, что команды ведут себя по-разному внутри (...)
-заключенных тел for /f
циклов.
В частности, внутристрочный символ ^
в "$string = '(?m)^!string[%%a]!=.*';" ^
— даже если он находится внутри строки "..."
— по необъяснимым причинам не используется дословно и требует экранирования как ^^
.
То есть замена строки"$string = '(?m)^!string[%%a]!=.*';" ^
в коде вашего вопроса с"$string = '(?m)^^!string[%%a]!=.*';" ^
должен решить вашу проблему.
Отступим назад: если вам все равно нужно выполнить большую часть сценария в PowerShell, почему бы не сделать все это в PowerShell? Он имеет более разумные конструкции циклов.