【问题标题】:Using Powershell to replace multiple strings in multiple files & folders使用 Powershell 替换多个文件和文件夹中的多个字符串
【发布时间】:2015-11-07 22:45:43
【问题描述】:

我有一个 CSV 文件中的字符串列表。格式为:

OldValue,NewValue
223134,875621
321321,876330
....

并且该文件包含几百行(每个 OldValue 都是唯一的)。我需要处理多个文件夹和子文件夹中多个文本文件的更改。我对文件夹、文件和文本行数的最佳猜测是 - 15 个文件夹,每个文件夹中大约有 150 个文本文件,每个文件夹中大约有 65,000 行文本(每个文本文件在 400-500 行之间)。

我将对数据进行 2 次传递,除非我可以一次完成。第一遍是生成一个文本文件,我将使用它作为检查列表来查看我的更改。第二遍是实际在文件中进行更改。另外,我只想更改出现字符串的文本文件(不是每个文件)。

我正在使用以下 Powershell 脚本来浏览文件并生成所需更改的列表。脚本运行,但速度非常慢。我还没有研究替换逻辑,但我认为它与我所拥有的相似。

# replace a string in a file with powershell
[reflection.assembly]::loadwithpartialname("Microsoft.VisualBasic") | Out-Null

Function Search {
  # Parameters $Path and $SearchString
  param ([Parameter(Mandatory=$true, ValueFromPipeline = $true)][string]$Path,
  [Parameter(Mandatory=$true)][string]$SearchString
  )
  try {
    #.NET FindInFiles Method to Look for file

    [Microsoft.VisualBasic.FileIO.FileSystem]::GetFiles(
    $Path,
    [Microsoft.VisualBasic.FileIO.SearchOption]::SearchAllSubDirectories,
    $SearchString
    )
  } catch { $_ }

}


if (Test-Path "C:\Work\ListofAllFilenamesToSearch.txt") {  # if file exists
    Remove-Item "C:\Work\ListofAllFilenamesToSearch.txt"
    }
if (Test-Path "C:\Work\FilesThatNeedToBeChanged.txt") {  # if file exists
    Remove-Item "C:\Work\FilesThatNeedToBeChanged.txt"
    }

$filefolder1 = "C:\TestFolder\WorkFiles"
$ftype = "*.txt"
$filenames1 = Search $filefolder1 $ftype

$filenames1 | Out-File "C:\Work\ListofAllFilenamesToSearch.txt" -Width 2000

if (Test-Path "C:\Work\FilesThatNeedToBeChanged.txt") {  # if file exists
    Remove-Item "C:\Work\FilesThatNeedToBeChanged.txt"
    }

(Get-Content "C:\Work\NumberXrefList.CSV" |where {$_.readcount -gt 1}) | foreach{
    $OldFieldValue, $NewFieldValue = $_.Split("|")
    $filenamelist = (Get-Content "C:\Work\ListofAllFilenamesToSearch.txt" -ReadCount 5) #| 
    foreach ($j in $filenamelist) {
    #$testvar = (Get-Content $j )
    #$testvar = (Get-Content $j -ReadCount 100)
    $testvar = (Get-Content $j -Delimiter "\n")
            Foreach ($i in $testvar)
            {
            if ($i -imatch $OldFieldValue) {
                $j + "|" + $OldFieldValue + "|" + $NewFieldValue | Out-File "C:\Work\FilesThatNeedToBeChanged.txt" -Width 2000 -Append
                }
            }
    }
}

$FileFolder = (Get-Content "C:\Work\FilesThatNeedToBeChanged.txt" -ReadCount 5)

Get-ChildItem $FileFolder -Recurse |
select -ExpandProperty fullname |
foreach {
   if (Select-String -Path $_  -SimpleMatch $OldFieldValue -Debug -Quiet) {
      (Get-Content $_) |
      ForEach-Object {$_ -replace $OldFieldValue, $NewFieldValue }|
      Set-Content $_ -WhatIf
    }
}

在上面的代码中,我用Get-Content - default-ReadCount-Delimiter 尝试了几件事 - 试图避免内存不足错误。

我唯一可以控制的是新旧替换字符串文件的长度。有没有办法在 Powershell 中做到这一点?有更好的选择/解决方案吗?我正在运行 Windows 7,Powershell 3.0 版。

【问题讨论】:

    标签: powershell text replace scripting cmdlets


    【解决方案1】:

    您的主要问题是您一遍又一遍地阅读文件以更改每个条款。您需要反转替换项的循环和文件的循环。此外,预加载 csv。比如:

    $filefolder1 = "C:\TestFolder\WorkFiles"
    $ftype = "*.txt"
    $filenames = gci -Path $filefolder1 -Filter $ftype -Recurse
    
    $replaceValues = Import-Csv -Path "C:\Work\NumberXrefList.CSV"
    
    foreach ($file in $filenames) {
        $contents = Get-Content -Path $file
    
        foreach ($replaceValue in $replaceValues) {    
            $contents = $contents -replace $replaceValue.OldValue, $replaceValue.NewValue
        }
    
        Copy-Item $file "$file.old"
        Set-Content -Path $file -Value $contents
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 2011-03-25
      • 2021-03-20
      • 2022-01-25
      • 1970-01-01
      • 1970-01-01
      • 2017-02-25
      相关资源
      最近更新 更多