PowerShell: Set-Content имеет проблемы с уже используемым файлом

Я работаю над сценарием PowerShell, который находит все файлы с ШАБЛОНОМ в заданном КАТАЛОГЕ, распечатывает соответствующие строки документа с выделенным ШАБЛОНОМ, а затем заменяет ШАБЛОН предоставленным словом ЗАМЕНА, а затем сохраняет файл обратно. Таким образом, он фактически редактирует файл.

За исключением того, что я не могу заставить его изменить файл, потому что 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. Конечно, часть кода в этом блоке теперь немного искажена из-за того, что я пытался решить проблему, а затем остановился, но имейте в виду цель этой части скрипта. Я хочу получить содержимое, заменить слова, а затем сохранить измененный текст обратно в файл, из которого я его получил.

Любая помощь вообще будет принята с благодарностью.


person Eli Wilson    schedule 20.04.2012    source источник


Ответы (3)


Удалил мой предыдущий ответ, заменив его следующим:

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

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

Примечание:

  • Круглые скобки вокруг Get-Content гарантируют, что файл проглотится за один раз (и, следовательно, будет закрыт).
  • Конвейер для последующих команд, а не встраивание.
  • Некоторые из ваших команд были удалены, чтобы убедиться, что это простой тест.
person yamen    schedule 20.04.2012
comment
Это продолжало выдавать мне ошибку, связанную с количеством скобок, но любое их перемещение было бесполезным. Тем не менее, мне это нравится намного больше, и я определенно буду использовать его, конечно, с некоторыми изменениями. Большое спасибо. Я все еще не заставил скрипт работать полностью, но я думаю, что со всеми этими модификациями я стал намного ближе. - person Eli Wilson; 21.04.2012
comment
Скобки вокруг Get-Content были для меня ключевыми - person Pete Baughman; 30.04.2015

Просто предложение, но вы можете попробовать посмотреть документацию для блока кода параметров. Существует более эффективный способ убедиться, что параметр введен, если он вам нужен, и выдать сообщение об ошибке, если пользователь этого не делает.

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

person Community    schedule 20.04.2012

Хорошо, я, наконец, сел и просто последовательно набрал все в PowerShell, а затем использовал это для создания своего сценария.

На самом деле это было очень просто;

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

Спасибо за вашу помощь, ребята.

person Eli Wilson    schedule 22.04.2012