PowerShell:Set-Content在处理“文件已在使用中”时遇到问题

6
我正在编写一个PowerShell脚本,用于在给定目录中查找所有包含PATTERN的文件,并打印出相关行,并将PATTERN替换为提供的REPLACE单词,然后保存文件。因此,它实际上编辑了文件。
但是,我无法更改文件,因为Windows会抱怨文件已经被打开。我尝试了几种方法来解决这个问题,但始终遇到这个问题。也许有人可以帮忙:
param(
    [string] $pattern = ""
    ,[string] $replace = ""
    ,[string] $directory ="."
    ,[switch] $recurse = $false
    ,[switch] $caseSensitive = $false)

if($pattern -eq $null -or $pattern -eq "")
{
    Write-Error "Please provide a search pattern." ; return
}

if($directory -eq $null -or $directory -eq "")
{
    Write-Error "Please provide a directory." ; return
}

if($replace -eq $null -or $replace -eq "")
{
    Write-Error "Please provide a string to replace." ; return
}

$regexPattern = $pattern
if($caseSensitive -eq $false) { $regexPattern = "(?i)$regexPattern" }
$regex = New-Object System.Text.RegularExpressions.Regex $regexPattern

function Write-HostAndHighlightPattern([string] $inputText)
{
    $index = 0
    $length = $inputText.Length
    while($index -lt $length)
    {
        $match = $regex.Match($inputText, $index)
        if($match.Success -and $match.Length -gt 0)
        {
            Write-Host $inputText.SubString($index, $match.Index) -nonewline
            Write-Host $match.Value.ToString() -ForegroundColor Red -nonewline
            $index = $match.Index + $match.Length
        }
        else
        {
            Write-Host $inputText.SubString($index) -nonewline
            $index = $inputText.Length
        }
    }
}

Get-ChildItem $directory -recurse:$recurse |
    Select-String -caseSensitive:$caseSensitive -pattern:$pattern |    
    foreach {
        $file = ($directory + $_.FileName)
        Write-Host "$($_.FileName)($($_.LineNumber)): " -nonewline
        Write-HostAndHighlightPattern $_.Line
        %{ Set-Content $file ((Get-Content $file) -replace ([Regex]::Escape("[$pattern]")),"[$replace]")}
        Write-Host "`n"
        Write-Host "Processed: $($file)"
    }

问题出现在最后一段代码中,就在 Get-ChildItem 调用那里。当然,由于我试图修复问题然后停止,所以该块中的某些代码现在有点混乱,但请记住脚本该部分的意图。我想获取内容,替换单词,然后将修改后的文本保存回我从中获取它的文件中。
非常感谢您的任何帮助。
3个回答

7

我删除了之前的回答,并用这个回答替换它:

Get-ChildItem $directory -recurse:$recurse
foreach {        
    $file = ($directory + $_.FileName)

    (Get-Content $file) | Foreach-object {
        $_ -replace ([Regex]::Escape("[$pattern]")),"[$replace]")
    } | Set-Content $file
}

注意:
  • 使用括号将Get-Content包围,以确保文件一次性读入(从而关闭文件)。
  • 使用管道将命令连接起来,而不是内嵌。
  • 为了确保测试简单,删除了某些命令。

它一直给我一个与括号数量有关的错误,但是无论如何移动它们都是徒劳的。然而,我更喜欢这个,并且肯定会使用它,当然还要进行一些修改。非常感谢。我仍然没有完全让脚本工作,但我认为通过所有这些修改,我离成功更近了。 - Eli Wilson
括号在Get-Content周围对我来说是关键的 - Pete Baughman

1

好的,我终于坐下来,在PowerShell中按顺序输入了所有内容,然后用它来制作我的脚本。

实际上这非常简单;

$items = Get-ChildItem $directory -recurse:$recurse
$items |
foreach {
    $file = $_.FullName
    $content = get-content $file
    $newContent = $content -replace $pattern, $replace
    Set-Content $file $newcontent
}

感谢大家的帮助。


0

仅供参考,您可以尝试查看参数代码块的文档。有一种更有效的方法来确保输入参数(如果需要)并在用户未输入时抛出错误消息。

About_throw: http://technet.microsoft.com/en-us/library/dd819510.aspx About_functions_advanced_parameters: http://technet.microsoft.com/en-us/library/dd347600.aspx

还有关于始终使用Write-Host的问题:http://powershell.com/cs/blogs/donjones/archive/2012/04/06/2012-scripting-games-commentary-stop-using-write-host.aspx


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接