PowerShell: ตั้งค่าเนื้อหาที่มีปัญหากับไฟล์ที่ใช้งานอยู่แล้ว

ฉันกำลังทำงานกับสคริปต์ PowerShell ที่จะค้นหาไฟล์ทั้งหมดที่มี PATTERN ภายใน DIRECTORY ที่กำหนด พิมพ์บรรทัดที่เกี่ยวข้องของเอกสารโดยที่ 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 แน่นอนว่าโค้ดบางส่วนในบล็อกนั้นตอนนี้เสียหายเล็กน้อยเนื่องจากฉันพยายามแก้ไขปัญหาแล้วหยุดทำงาน แต่อย่าลืมคำนึงถึงจุดประสงค์ของส่วนนั้นของสคริปต์ด้วย ฉันต้องการรับเนื้อหา แทนที่คำ จากนั้นบันทึกข้อความที่แก้ไขกลับไปยังไฟล์ที่ฉันได้รับ

ความช่วยเหลือใด ๆ เลยจะได้รับการชื่นชมอย่างมาก


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