特定の拡張子を持つすべてのファイルを検索して置き換えるPowerShellスクリプト


123

私はそのようにネストされたWindows Server 2008の設定ファイルをいくつか持っています:

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config

私の構成では、次のような文字列置換を行う必要があります。

<add key="Environment" value="Dev"/>

となります:

<add key="Environment" value="Demo"/>

バッチスクリプトを使用することを考えましたが、これを行う良い方法はありませんでした。また、PowerShellスクリプトを使用すると、これを簡単に実行できると聞きました。検索/置換の例を見つけましたが、C:\ Projectsディレクトリ内のすべてのフォルダーを走査し、拡張子が「.config」のファイルを見つける方法を望んでいました。見つかった場合は、文字列値を置き換えます。

これを行う方法を見つけるための優れたリソース、または洞察を提供できるPowerShellの教祖


1
対処方法、または対処する必要のあるファイルに奇妙なフォーマットの問題があったかどうかをお知らせください。この問題の良い点の1つは、実稼働コードに影響を与えずにテストできることです
Robben_Ford_Fan_boy

回答:


178

ここで私の頭の上での最初の試み。

$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
    (Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace "Dev", "Demo" } |
    Set-Content $file.PSPath
}

3
提供されたソリューションのテストはすべてうまくいったことを付け加えたいのですが、これが読みやすさの点で最も簡単でした。これを同僚に渡すと、彼は何が起こっているのか簡単に理解できました。援助をありがとう。
ブランドン、

11
これをサブディレクトリのファイルで機能させるには、「。PSPath」が必要です。興味深いことに、get-contentの周りに()を付けずにこの作業を行おうとすると、ファイルがロックされていたため、write-contentで失敗しました。
フランクSchwieterman、2010年

25
ショートバージョン(よく使用されるエイリアス):ls *.config -rec | %{ $f=$_; (gc $f.PSPath) | %{ $_ -replace "Dev", "Demo" } | sc $f.PSPath }
Artyom 2013

5
@Artyomは忘れないでください.ls。自分で刺された。
Pureferret、2015

5
UnauthorizedAccessExceptionは、*。configを削除してすべてのファイルで実行すると、フォルダーが原因で発生する場合もあります。Get-ChildItemに-Fileフィルターを追加できます...それを理解するのにしばらく時間がかかりました
Amir Katz

32

PowerShellは良い選択です;)与えられたディレクトリのファイルを列挙し、それらを読み、処理することは非常に簡単です。

スクリプトは次のようになります。

Get-ChildItem C:\Projects *.config -recurse |
    Foreach-Object {
        $c = ($_ | Get-Content) 
        $c = $c -replace '<add key="Environment" value="Dev"/>','<add key="Environment" value="Demo"/>'
        [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
    }

コードを複数行に分割して読みやすくしました。の代わりにSet-Contentを使用することもできますが[IO.File]::WriteAllText、最後に新しい行が追加されることに注意してください。WriteAllTextあなたはそれを避けることができます。

それ以外の場合、コードは次のようになります$c | Set-Content $_.FullName


14

このアプローチはうまくいきます:

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
}
  • 「古い」と「新しい」を対応する値に変更します(または変数を使用します)。
  • 括弧を忘れないでください。括弧がないと、アクセスエラーが発生します。

だから私は、簡潔な表現のために、この1と一緒に行きました-しかし、私は交換していたGet-Content $_Get-Content $_.FullName、との等価Set-Contentそれがルートではありませんでしたファイルを処理するため。
Matt Whitfield

11

私はxmlとxpathで行きます:

dir C:\Projects\project_*\project*.config -recurse | foreach-object{  
   $wc = [xml](Get-Content $_.fullname)
   $wc.SelectNodes("//add[@key='Environment'][@value='Dev']") | Foreach-Object {$_.value = 'Demo'}  
   $wc.Save($_.fullname)  
}

11

このpowershellの例では、フォルダーとそのサブフォルダー内の文字列「\ foo \」のすべてのインスタンスを検索し、「\ foo \」を「\ bar \」に置き換え、文字列「\ foo \」を含まないファイルを再書き込みしません"この方法では、文字列が見つからなかったファイルの最終更新日時スタンプを破棄しません。

Get-ChildItem  -Path C:\YOUR_ROOT_PATH\*.* -recurse 
 | ForEach {If (Get-Content $_.FullName | Select-String -Pattern '\\foo\\') 
           {(Get-Content $_ | ForEach {$_ -replace '\\foo\\', '\bar\'}) | Set-Content $_ }
           }

7

@Artyomのコメントは役に立ちましたが、残念ながら彼は回答を投稿していません。

これは、私の意見では、受け入れられた回答の短縮版です。

ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}

1
他の誰かが私と同じようにこれに遭遇した場合-バッチファイルからこれを直接実行するために- このようなコマンドを実行するときforeach-object%エイリアスの代わりに使用すると役立つ場合があります。それ以外の場合は、エラーになる可能性がありますExpressions are only allowed as the first element of a pipeline
ダスティン・ハルステッド

ショートは常に良いとは限りません。ロングバージョンで何が起こっているかはより明確です。
Nick N.

@NickN。そうですね。それはあなたの目的が何であるかに依存します。私はPOBとしてフラグを立てます;)
M--

6

ファイル内のテキストを置き換えるための小さなヘルパー関数を作成しました。

function Replace-TextInFile
{
    Param(
        [string]$FilePath,
        [string]$Pattern,
        [string]$Replacement
    )

    [System.IO.File]::WriteAllText(
        $FilePath,
        ([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement)
    )
}

例:

Get-ChildItem . *.config -rec | ForEach-Object { 
    Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new' 
}

4

再帰的な置換を行う場合、パスとファイル名を含める必要があります。

Get-ChildItem -Recurse | ForEach {  (Get-Content $_.PSPath | 
ForEach {$ -creplace "old", "new"}) | Set-Content $_.PSPath }

このwilは、現在のディレクトリのフォルダーのすべてのファイルで、すべての「古い」を「新しい」大文字と小文字を区別して置き換えます。


あなたの答えの ".PSPath"の部分は本当に私を助けました。しかし、内側の「{$」を「$ _」に変更する必要がありました。私はあなたの答えを編集しますが、私は-creplace部分を使用していません-.PSPathで承認された回答を使用しています
aaaa bbbb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.