用于替换目录中每个文件中的一行的 Powershell 脚本不起作用

Powershell scipt for replacing a line in every file in directory doesn't work

我想制作一个 powershell 脚本,以便更快地更改多个文件中的一行。

真的是第一次尝试做这样的东西。 我基本上想做什么:

  1. Select 目录中具有“.xml”扩展名的所有文件
  2. 遍历每个文件的每一行并检查它是否包含以下文本(示例:<package>true</package>)/
  3. 那我想把上面的例子文字改成新的文字(例子:<package>false</package>) 此外,如果文件不包含 <package>true</package> 我还想添加 <package>false</package>
  4. 之后它应该只保存文件而不是在其他地方创建新文件。

我以前从未真正使用过 powershell,所以我做了一些挖掘并想出了这段代码:

$files = Get-ChildItem –Path 'C:\test-XML\XML' -Recurse -Filter *.xml 
$tempFilePath = 'C:\test-XML\newXml'
$find = '<packag>true</package>'
$replace = '<packag>false</package>'


foreach ($f in $files){
   (Get-Content $f) -replace $find, $replace | Add-Content -Path $tempFilePath
}

使用这段代码,我应该能够获取目录中的所有文件,然后遍历它并用较新的文本更改文本。但它不起作用,也没有涵盖我使任务更容易所需的所有要点。

有没有人有见解让它发挥作用,甚至比现在更好。

一般来说,值得留意zett42's advice: For processing XML files, it is more robust to use a dedicated XML parser, notably [xml] (System.Xml.XmlDocument)。

如果纯文本处理是一个选项 - 听起来它适合您 - 您可以使用以下方法,它 就地 更新所有文件;它针对性能进行了优化:

Get-ChildItem –LiteralPath C:\test-XML\XML -Recurse -Filter *.xml |
  ForEach-Object {
    # CAUTION: This updates files *in place*.
    #          Adjust the encoding as needed.
    Set-Content -Encoding Utf8 $_.FullName -Value (
      (Get-Content -Raw $_.FullName) -replace '<package>true</package>', '<package>false</package>'
    )
  }

注:

  • 您的代码的主要问题可能只是一个拼写错误:<packag> -> <package>.

  • 文件内容更新到位,所以最好先备份文件,以防万一。如果写回更新内容的过程被中断,则存在文件损坏的假设风险。

  • 为了效率,需要Get-Content -Raw reads the entire file into a single, multi-line string (the default behavior is to output an array of lines, which is much slower), so that only a single 。如果输入字符串中没有匹配项,则按原样返回。

  • 请注意,无论输入文件使用何种编码,PowerShell 在输出时始终使用文件写入 cmdlet 的 默认 字符编码,因此显式使用Set-Content
    -Encoding 参数。

    • 有关 Windows PowerShell 与 PowerShell [Core] v6+ 中默认编码的更多信息,请参阅
  • 注意更新的内容是传递给Set-Content-Value参数而不是通过管道($content | Set-Content ...);虽然这里的性能差异不大,但假设只传递了 one 字符串,使用行数组处理它会:如果,比方说,$content 包含数组行写入文件,Set-Content ... -Value $content 将比 $content | Set-Content ...

    快得多
  • 为简洁起见,Set-ContentGet-Content 调用传递文件名参数 positionally,它隐式绑定到 -Path参数,严格来说接受wildcard patterns;通常,即使您传递 文字 文件名,它也会按预期工作,但更可靠的方法是使用 -LiteralPath 参数,如 Get-ChildItem 调用中所示多于;具体来说,包含 [] 的文字文件名会导致 -Path 参数的错误解释,除非它们是 escaped .