Powershell5 通过组合 foreach、begin、process 和 replace 命令来压缩代码

Powershell5 Compact code by combining foreach, begin, process, and replace command

我可以用更少的代码得到相同的结果吗? 代码搜索 sample.bat 字符串 AROUND LINE {1-9999} 和 LINE2 {1-9999} 并将 {1-9999} 替换为代码所在的 {line number}。

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

您可以使用一个正则表达式完成这项工作:

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++ returns 当前 $lc 值并在之后将其递增 1,从而无需 $lc += 1 语句。
此外,我已将 Out-File 替换为 Set-Content,因为它们在保存 字符串 方面的功能相同,但后者更快。
最后,要匹配一个或多个数字,请使用\d+而不是\d*

关于 $_ -replace '(?<=AROUND LINE |LINE2 )\d+', $lc++ 的注释:

  • 正则表达式 (?<=AROUND LINE |LINE2 )\d+ 使用后视断言 ((?<=...) 来查找 (|) 字符串 AROUND LINE  或字符串 LINE2 在一位或多位 (+) 位 (\d) 之前。

    • 后视断言在设计上不被视为匹配的一部分,因此被替换的子字符串仅限于 运行 位数字,即仅 数字.
  • $lc++ 是替换操作数:它 returns 变量 $lc 的当前值并在 之后增加它的值 ;请注意,即使 $lc 是一个 数字 ([int]),PowerShell 会自动将其转换为字符串以进行替换。


不过,一般来说,您可以简单地 -replace 操作:

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