【问题标题】:How to Find Replace Multiple strings in multiple text files using Powershell如何使用 Powershell 查找替换多个文本文件中的多个字符串
【发布时间】:2014-09-29 14:26:48
【问题描述】:

我是脚本和 Powershell 新手。我最近一直在做一些研究,并试图构建一个脚本来查找/替换一堆文本文件中的文本(每个文本文件都有代码,不超过 4000 行)。但是,我想将 FindString 和 ReplaceString 保留为变量,因为有多个值,而这些值又可以从单独的 csv 文件中读取。

我想出了这段代码,它是功能性的,但我想知道这是否是上述要求的最佳解决方案。我想在脚本中保持 FindString 和 ReplaceString 作为正则表达式兼容,因为我也想查找/替换模式。 (我还没有用正则表达式模式测试它)

Input.csv 的示例内容:(csv 中的对象数量可能从 50 到 500 不等)

FindString  ReplaceString
AA1A    171PIT9931A
BB1B    171PIT9931B
CC1C    171PIT9931E
DD1D    171PIT9932A
EE1E    171PIT9932B
FF1F    171PIT9932E
GG1G    171PIT9933A

代码

$Iteration = 0
$FDPATH = 'D:\opt\HMI\Gfilefind_rep'
#& 'D:\usr\fox\wp\bin\tools\fdf_g.exe' $FDPATH\*.fdf
$GraphicsList = Get-ChildItem -Path $FDPATH\*.g | ForEach-Object FullName
$FindReplaceList = Import-Csv -Path $FDPATH\Input.csv
foreach($Graphic in $Graphicslist){
    Write-Host "Processing Find Replace on : $Graphic"
    foreach($item in $FindReplaceList){
    Get-Content $Graphic | ForEach-Object { $_ -replace "$($item.FindString)", "$($item.ReplaceString)" } | Set-Content ($Graphic+".tmp")
        Remove-Item $Graphic
        Rename-Item ($Graphic+".tmp") $Graphic
        $Iteration = $Iteration +1
        Write-Host "String Replace Completed for $($item.ReplaceString)"
    }
}

我浏览了 Stackoverflow 中的其他帖子,并收集了有价值的输入,并以此为基础构建了代码。 This post from Ivo Bosticky 非常接近我的要求,但我必须在嵌套的 foreach 循环中执行相同的操作,并将查找/替换字符串作为从外部源读取的变量。

总结一下,

  1. 我想知道上面的代码是否可以针对 执行,因为我觉得执行需要很长时间。 (我更喜欢 现在不使用别名,因为我刚刚开始,很好 具有长而实用的脚本,而不是简洁的脚本 很难理解)
  2. 我想添加正在执行的迭代次数 循环。我能够将当前的迭代号添加到 控制台,但不知道如何通过管道输出 Measure-Command 到一个变量上,可以在 Write-Host 中使用 命令。我还想显示代码花费的时间 执行,完成时。

感谢您花时间阅读此查询。非常感谢您的支持!

【问题讨论】:

  • 别名根本不会改变性能,在脚本中使用别名是一种反模式;首选做法是使用完整的 cmdlet 和参数名称。使用交互式 shell 时可以使用别名,但不能保存您将来和其他地方使用的脚本/模块。
  • 完全同意 Alroc。我的意思是说,虽然我要求对脚本进行优化,但我希望通过使用所用 cmdlet 的相应别名来优化它的性能(效率)而不是缩短它的方法。

标签: regex powershell optimization replace find


【解决方案1】:

首先,除非您的替换字符串将包含换行符(这会改变行边界),否则我建议您只获取和设置每个$Graphic 文件的内容一次,并一次完成所有替换。这也将减少文件重命名和删除。

其次,将$item.FindString$item.ReplaceString 直接传递给-replace 运算符比调用模板引擎将值注入字符串文字会更快(可能会稍微)。

第三,除非您确实需要将输出直接发送到控制台而不是转到正常的输出流,否则我会避免使用Write-Host。见Write-Host Considered Harmful

第四,您实际上可能想要删除每次查找和替换都会调用的Write-Host,因为它可能会对整体执行时间产生相当大的影响,具体取决于有多少替换。

你最终会得到这样的结果:

$timeTaken = (measure-command {
    $Iteration = 0
    $FDPATH = 'D:\opt\HMI\Gfilefind_rep'
    #& 'D:\usr\fox\wp\bin\tools\fdf_g.exe' $FDPATH\*.fdf
    $GraphicsList = Get-ChildItem -Path $FDPATH\*.g | ForEach-Object FullName
    $FindReplaceList = Import-Csv -Path $FDPATH\Input.csv
    foreach($Graphic in $Graphicslist){
        Write-Output "Processing Find Replace on : $Graphic"
        Get-Content $Graphic | ForEach-Object { 
        foreach($item in $FindReplaceList){
            $_ = $_ -replace $item.FindString, $item.ReplaceString
        }       
        $Iteration += 1
        $_
        } | Set-Content ($Graphic+".tmp")
        Remove-Item $Graphic
        Rename-Item ($Graphic+".tmp") $Graphic
    }
}).TotalMilliseconds

我还没有测试过,但它应该运行得更快一些,而且它会将经过的时间保存到一个变量中。

【讨论】:

    猜你喜欢
    • 2011-03-25
    • 1970-01-01
    • 2015-11-07
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    • 2022-01-25
    相关资源
    最近更新 更多