2013-06-28 46 views
1

我正在放置一個簡單的PowerShell腳本,它將查找/替換各種數量的關鍵字。如果找到關鍵字,則應該用不同的短語替換它們。ForEach-Object使用Powershell從文件中刪除行

這適用於存在關鍵字的行,但腳本正在刪除關鍵字不存在的行;這不是我想要的行爲。

我的期望是它會取代KEYWORDS並保持所有其他東西不變。

腳本:

#*============================================= 
#* Script Name: SQLFILE_find_and_replace.ps1 
#* Created: 12-Jun-2013 
#*============================================= 
#* Purpose: Intended for SQLFILE scripts 
#* generated from a datapump dump file. 
#* 
#* Will find and replace "Create [Keyword]" 
#* with "Create or Replace [Keyword]" within a 
#* specified file. 
#*============================================= 

#Keywords for find/replace to act on; adjust as necessary. 
$KEYWORDS = @("PROCEDURE","PACKAGE","FUNCTION","TYPE","SEQUENCE","VIEW","DATABASE LINK","TRIGGER") 

# Get-FileName from http://blogs.technet.com/b/heyscriptingguy/archive/2009/09/01/hey-scripting-guy-september-1.aspx 
Function Get-FileName($initialDirectory) 
{ 
    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | 
    Out-Null 

    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog 
    $OpenFileDialog.initialDirectory = $initialDirectory 
    $OpenFileDialog.filter = "All files (*.*)| *.*" 
    $OpenFileDialog.ShowDialog() | Out-Null 
    $OpenFileDialog.filename 
} #end function Get-FileName 

#Ask user for file 
$FILENAMELOC=Get-FileName -initialDirectory "C:\" 


Write-Progress -Activity "Loading file" -status "$FILENAMELOC" -percentComplete 0 

$file = (Get-Content -Path $FILENAMELOC) 
$lines = ($file | Measure-Object) 
$lineprocessed = 0 

$file | 
    ForEach-Object { 
     $lineprocessed = $lineprocessed + 1 
     ForEach ($KEYWORD in $KEYWORDS) { 
      if ($_.indexof("$KEYWORD") -ge 0) { 
       if ($KEYWORD -eq "SEQUENCE" -and $_.indexof("MINVALUE") -ge 0) { 
        $SEQUENCENAME = $_.Substring($_.indexof("$KEYWORD"),$_.indexof("MINVALUE")-$_.indexof("$KEYWORD")-1) 
        $DROP = "DROP "+$SEQUENCENAME +";" 
        $CREATE = "CREATE "+$SEQUENCENAME +";" 
        $SQL = $DROP+"`r`n"+$CREATE 
        $_ -replace "CREATE $KEYWORD", $SQL 
       } 
       else { 
        $_ -replace "CREATE $KEYWORD", "CREATE OR REPLACE $KEYWORD" 
       } 
      } 
     } 
     Write-Progress -Activity "Replacing keywords" -status "Running" -percentComplete ([System.Math]::Round((($lineprocessed/$lines.count)*100),2)) 
    } | 
    Set-Content $FILENAMELOC 

測試文件:

This is a test. 
CREATE PROCEDURE Blah 
CREATE TRIGGER Boblawbla 
CREATE FUNCTION 
This is another test 

Watch me disappear. 

結果:

CREATE OR REPLACE PROCEDURE Blah 
CREATE OR REPLACE TRIGGER Boblawbla 
CREATE OR REPLACE FUNCTION 

這是一個Windows 7箱。

回答

2

這是您的罪魁禍首:

if ($_.indexof("$KEYWORD") -ge 0) { 
    if ($KEYWORD -eq "SEQUENCE" -and $_.indexof("MINVALUE") -ge 0) { 
    ... 
    $_ -replace "CREATE $KEYWORD", $SQL 
    } else { 
    $_ -replace "CREATE $KEYWORD", "CREATE OR REPLACE $KEYWORD" 
    } 
} 

只有2 $_ -replace ...產生輸出管道重定向到Set-Content。您似乎認爲-replace運算符修改了$_中的內容,並且Write-Host $_將該行回顯到管道中。情況並非如此。 $_ -replace ...取值爲$_,替換它找到的匹配項,並將修改後的字符串寫入STDOUT。 Write-Host將消息寫入控制檯,而不是STDOUT。

添加else分支呼應不包含任何關鍵字的線條和你應該罰款:

if ($_.indexof("$KEYWORD") -ge 0) { 
    if ($KEYWORD -eq "SEQUENCE" -and $_.indexof("MINVALUE") -ge 0) { 
    ... 
    $_ -replace "CREATE $KEYWORD", $SQL 
    } else { 
    $_ -replace "CREATE $KEYWORD", "CREATE OR REPLACE $KEYWORD" 
    } 
} else { 
    $_ 
} 

你讓這樣太複雜了,雖然。像這樣的東西應該足夠了(如果我正確地分析你的代碼):

(Get-Content $FILENAMELOC) | % { 
    $_ -replace 'CREATE SEQUENCE (\S*)', "DROP `$1;`r`nCREATE `$1" ` 
    -replace 'CREATE (PROCEDURE|PACKAGE|FUNCTION|TYPE|VIEW|DATABASE LINK|TRIGGER)', 'CREATE OR REPLACE $1' 
} | Set-Content $FILENAMELOC 
+0

其實,寫主機是我的「調試」的方式,我並沒有考慮將管道設置的內容,但我刪除即從上面去除歧義。 –

+0

你說得很對。但是,如果我在那裏放了一個else,而它爲每行添加一個結果,它會這樣做8次(每個關鍵字一次)。你有建議如何解決這個問題嗎?我覺得我被困在兩個選項中的一個之間 - 循環遍歷文件8次(每個關鍵字一次)或循環一次文件,並循環遍歷每行8次。你的解釋是非常有幫助的,我確實認爲 - 取而代之的是$ _;關鍵是要知道情況並非如此。感謝那 –

+0

查看更新的答案。 –