通过组合foreach,begin,process和replace命令的Powershell5 Compact代码

时间:2019-02-19 02:09:04

标签: powershell powershell-v5.0

我可以用更少的代码获得相同的结果吗? 该代码在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

1 个答案:

答案 0 :(得分: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)。

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


不过,通常,您可以简单地 chain -replace操作:

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