如何查找使用Powershell在多个文本文件中替换多个字符串 [英] How to Find Replace Multiple strings in multiple text files using Powershell

查看:406
本文介绍了如何查找使用Powershell在多个文本文件中替换多个字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不熟悉脚本和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'
#& amp ; '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($ Graphics中的$ Graphic){
Write-Host正在处理查找替换:$图形
foreach($ FindReplaceList中的$ item){
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字符串替换已完成$($ item.ReplaceString)
}
}

我在Stackoverflow中通过了其他帖子,收集了基于代码构建的有价值的输入。 本文来自Ivo Bosticky 与我的要求非常接近,但是我必须在嵌套的foreach循环上执行相同的操作,查找/替换字符串作为从外部读取的变量。



总之,我想知道上面的代码是否可以针对
执行进行优化,因为我觉得执行需要很长时间。 (我现在比较喜欢
,现在不用别名了,因为我刚刚开始了,而且
有一个长而实用的脚本,而不是一个简单的
很难理解的
) li>
  • 我想在
    循环中添加正在执行的迭代次数。我能够将当前Iteration编号添加到
    控制台中,但无法计算如何将
    Measure-Command的输出传送到一个变量上,这个变量可用于Write-Host
    命令。我还想显示执行完代码
    所需的时间。

  • 感谢您花时间阅读这个查询。非常感谢您的支持!
    首先,除非您的替换字符串将包含换行符(这将改变行界限),我会建议只获取和设置每个 $ Graphic 文件的内容一次,并且一次完成所有替换。第二,通过 $ item.FindString 可能会(可能稍微快一些) code>和 $ item.ReplaceString 直接传递给 -replace 操作符,而不是调用模板引擎来注入第三,除非你真的需要输出直接到控制台,而不是去正常的输出流,我会避免写主机。请参阅写主机被认为是有害的



    第四,您可能实际上想要移除为每个查找和替换调用的 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($ Graphics中的$ Graphic) {
    写输出处理查找替换:$图形
    获取内容$图形| F orEach-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

    我没有测试过它,但它应该运行得更快一些,再加上它会保存已过时间到一个变量。


    I am new to scripting, and Powershell. I have been doing some study lately and trying to build a script to find/replace text in a bunch of text files (Each text file having code, not more than 4000 lines). However, I would like to keep the FindString and ReplaceString as variables, for there are multiple values, which can in turn be read from a separate csv file.

    I have come up with this code, which is functional, but I would like to know if this is the optimal solution for the aforementioned requirement. I would like to keep the FindString and ReplaceString as regular expression compatible in the script, as I would also like to Find/Replace patterns. (I am yet to test it with Regular Expression Pattern)

    Sample contents of Input.csv: (Number of objects in csv may vary from 50 to 500)

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

    The Code

    $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)"
        }
    }
    

    I have gone through other posts here in Stackoverflow, and gathered valuable inputs, based on which the code was built. This post from Ivo Bosticky came pretty close to my requirement, but I had to perform the same on a nested foreach loop with Find/Replace Strings as Variables reading from an external source.

    To summarize,

    1. I would like to know if the above code can be optimized for execution, since I feel it takes a long time to execute. (I prefer not using aliases for now, as I am just starting out, and am fine with a long and functional script rather than a concise one which is hard to understand)
    2. I would like to add the number of Iterations being carried out in the loop. I was able to add the current Iteration number onto the console, but couldn't figure how to pipe the output of Measure-Command onto a variable, which could be used in Write-Host Command. I would also like to display the time taken for code execution, on completion.

    Thanks for the time taken to read this Query. Much appreciate your support!

    解决方案

    First of all, unless your replacement string is going to contain newlines (which would change the line boundaries), I would advise getting and setting each $Graphic file's contents only once, and doing all replacements in a single pass. This will also result in fewer file renames and deletions.

    Second, it would be (probably marginally) faster to pass $item.FindString and $item.ReplaceString directly to the -replace operator rather than invoking the templating engine to inject the values into string literals.

    Third, unless you truly need the output to go directly to the console instead of going to the normal output stream, I would avoid Write-Host. See Write-Host Considered Harmful.

    And fourth, you might actually want to remove the Write-Host that gets called for every find and replace, as it may have a fair bit of effect on the overall execution time, depending on how many replacements there are.

    You'd end up with something like this:

    $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
    

    I haven't tested it but it should run a fair bit faster, plus it will save the elapsed time to a variable.

    这篇关于如何查找使用Powershell在多个文本文件中替换多个字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆