用于查找和替换具有特定扩展名的所有文件的PowerShell脚本

Bra*_*don 113 powershell scripting replace find

我在Windows Server 2008上嵌套了几个配置文件,如下所示:

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config
Run Code Online (Sandbox Code Playgroud)

在我的配置中,我需要像这样进行字符串替换:

<add key="Environment" value="Dev"/>
Run Code Online (Sandbox Code Playgroud)

会变成:

<add key="Environment" value="Demo"/>
Run Code Online (Sandbox Code Playgroud)

我考虑过使用批处理脚本,但没有好的方法可以做到这一点,我听说使用PowerShell脚本可以轻松执行此操作.我找到了find/replace的例子,但我希望有一种方法可以遍历我的C:\ Projects目录中的所有文件夹,并找到任何以'.config'扩展名结尾的文件.当它找到一个,我希望它替换我的字符串值.

有什么好的资源可以找到如何做到这一点或任何可以提供一些见解的PowerShell大师?

Rob*_*boy 166

这是我头脑中的第一次尝试.

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

  • 简短版本(使用的常用别名):`ls*.config -rec | %{$ f = $ _; (gc $ f.PSPath)| %{$ _ -replace"Dev","Demo"} | sc $ f.PSPath}` (24认同)
  • 为了在子目录中的文件中工作,您需要".PSPath".有趣的是,当我试图在get-content周围没有()时,它在写内容失败,因为文件被锁定了. (9认同)
  • @Artyom不要忘记`ls'之后的`.`.被我自己惹恼了. (4认同)
  • 如果您要删除*.config以在所有文件上运行,则UnauthorizedAccessException也可能由于文件夹而导致.您可以将-File过滤器添加到Get-ChildItem ......花了一段时间来弄清楚它 (4认同)
  • 我想补充说,测试所提供的解决方案都是有效的,但这个是最容易阅读的.我能够把它交给同事,他可以很容易地理解发生了什么.谢谢你的帮助. (3认同)

ste*_*tej 31

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"))
    }
Run Code Online (Sandbox Code Playgroud)

我将代码拆分为更多行,以便您可读.请注意,您可以使用Set-Content代替[IO.File]::WriteAllText,但最后会添加新行.有了WriteAllText你能避免它.

否则代码看起来像这样:$c | Set-Content $_.FullName.


Tol*_*lga 14

这种方法效果很好:

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
}
Run Code Online (Sandbox Code Playgroud)
  • 将"旧"和"新"更改为其对应的值(或使用变量).
  • 不要忘记括号 - 没有它,您将收到访问错误.

  • 所以我用这个来表达简洁 - 但我必须用 `Get-Content $_.FullName` 替换 `Get-Content $_` ,以及等效的 `Set-Content` 来处理那些不存在的文件t 在根。 (2认同)

Sha*_*evy 10

我会选择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)  
}
Run Code Online (Sandbox Code Playgroud)


小智 8

此PowerShell示例查找文件夹及其子文件夹中字符串"\ foo \"的所有实例,将"\ foo \"替换为"\ bar \"并且不重写REWRITE不包含字符串"\ 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 $_ }
           }
Run Code Online (Sandbox Code Playgroud)


M--*_*M-- 7

我发现@Artyom的评论很有用,但不幸的是他还没有发布答案.

这是我认为最佳版本的简短版本,接受的答案;

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

  • 万一其他人遇到这个问题,就像我一样——希望直接从批处理文件执行这个问题——在执行这样的命令时,使用“foreach-object”而不是“%”别名可能会有所帮助。否则,可能会导致错误:“表达式只能作为管道的第一个元素” (3认同)

Mar*_*ndl 5

我写了一个小助手函数来替换文件中的文本:

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

    [System.IO.File]::WriteAllText(
        $FilePath,
        ([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement)
    )
}
Run Code Online (Sandbox Code Playgroud)

例:

Get-ChildItem . *.config -rec | ForEach-Object { 
    Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new' 
}
Run Code Online (Sandbox Code Playgroud)


Gei*_*tad 5

进行递归替换时,需要包含路径和文件名:

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

这将在当前目录的文件夹的所有文件中将所有“旧”替换为“新”(区分大小写)。