Powershell5 Компактный код, объединяющий команды foreach, begin, process и replace

Могу ли я получить те же результаты с меньшим количеством кода? Код ищет в файле sample.bat строки AROUND LINE {1-9999} и LINE2 {1-9999} и заменяет {1-9999} на {номер строки}, на котором находится код.

sample.bat:

AROUND LINE 262
LINE2 1964

Старый код:

gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
  $_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
  $lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat
(gc $env:temp\results.bat) | foreach -Begin {$lc = 1} -Process {
  $_ -replace "LINE2 \d*", "LINE2 $lc";
  $lc += 1
} | Out-File -Encoding Ascii $env:temp\results.bat

Текущий код:

(gc $env:temp\sample.bat) | foreach -Begin {$lc = 1} -Process {
  $_ -replace "AROUND LINE \d*", "AROUND LINE $lc";
  $lc += 1
} | foreach -Begin {$lc = 1} -Process {
  $_ -replace "LINE2 \d*", "LINE2 $lc";
} | Out-File -Encoding Ascii $env:temp\sample.bat

Ожидаемые результаты:

AROUND LINE 1
LINE2 2

Фактические результаты:

AROUND LINE 1
LINE2 2

person somebadhat    schedule 19.02.2019    source источник


Ответы (1)


Вы можете сделать это с помощью одного регулярного выражения:

gc $env:temp\sample.bat | foreach -Begin {$lc = 1} -Process {
  $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++
} | Set-Content -Encoding Ascii $env:temp\results.bat

Обратите внимание, что я использую '...' (одинарные кавычки), а не "..." (двойные кавычки), чтобы заключить регулярное выражение, что предпочтительнее, чтобы исключить потенциальную путаницу, возникающую из-за того, что PowerShell сначала выполняет расширение строки (интерполяцию).
$lc++ возвращает текущее значение $lc и впоследствии увеличивает его на 1, устраняя необходимость в инструкции $lc += 1.
Кроме того, я заменил Out-File на Set-Content, поскольку они функционально одинаковы для сохранения строк, но последний быстрее.
Наконец, чтобы сопоставить одну или несколько цифр, используйте \d+, а не \d*.

Примечание к $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++:

  • Регулярное выражение (?<=AROUND LINE |LINE2 )\d+ использует утверждение ретроспективного просмотра ((?<=...) для поиска либо (|) строки AROUND LINE , либо строки LINE2  перед одной или несколькими (+) цифрами (\d).

    • The look-behind assertion is by design not considered part of the match, so that the substring getting replaced is limited to the run of digits, i.e., the number only.
  • $lc++ - операнд замены: он возвращает текущее значение переменной $lc и увеличивает его значение впоследствии; обратите внимание, что даже несмотря на то, что $lc является числом ([int]), PowerShell автоматически преобразует его в строку для замены.


Как правило, вы можете просто связать -replace операции:

# ...
$_ -replace 'AROUND LINE \d+', "AROUND LINE $lc" -replace 'LINE2 \d+', "LINE2 $lc"
++$lc
# ... 
person mklement0    schedule 19.02.2019