powershell / cmd命令用于查找和替换多个文件中多行的字符串

时间:2012-12-14 15:55:26

标签: windows powershell cmd replace

我之前从未使用过PowerShell,Google也没有给出我所需要的答案。我希望你们能帮助我。 我需要找到目录中的所有文件(包括子目录),这些文件有两行:

aaa aaa
bbb bbb

并将第二行替换为ccc

如果bbb bbb之后没有排aaa aaa行,则不应该进行替换。

这是我到目前为止所拥有的:

$line3 = "aaa[ ]*aaa[ ]*bbb[ ]*bbb"
Get-ChildItem -exclude *.bak -recurse *.txt | Where-Object {$_.Attributes -ne "Directory"} |
    ForEach-Object { 
        Copy-Item $_ "$($_).bak"; 
        $wholeFile = [IO.File]::ReadAllText("$_");
        $wholeFile = $wholeFile.replace("`n", " ");
        $wholeFile = $wholeFile.replace("`r", " ");
        $temp3 = $wholeFile | Select-String -pattern $line3 -quiet;
        if(($temp3 -eq "True")){
            (Get-Content $_)  -replace "bbb[ ]*bbb", "ccc" | Set-Content -path $_;
        }
        else{
            echo failed
        }
    }

我认为这个代码几乎可以工作,除非文件有2次出现“bbb bbb”:一个紧跟在“aaa aaa”之后,另一个没有“aaa aaa”。两条线都会被替换,我只需要更换第一条线。有什么方法可以解决它吗? 有经验的人可以告诉我,如果我错过了什么吗?我需要什么更简单/更短的解决方案?我在powershell中看到了很多简洁的单行解决方案。我的案子有什么类似的吗? 感谢

3 个答案:

答案 0 :(得分:2)

这是一个批处理解决方案:)

@echo off
setlocal enabledelayedexpansion
cd C:\folder
set aaa=false
for /r C:\folder %%a in (*) do (
for /f "tokens=1,2 delims= " %%x in (%%a) do (
if "!aaa!"=="true" (
if "%%x"=="bbb" if "%%y"=="bbb" (
echo ccc ccc >>temp.txt
del %%a /f /q
ren temp.txt %%~nxa
set aaa=false
)
) else (
if "%%x"=="aaa" if "%%y"=="aaa" set aaa=true
echo %%x %%y >>temp.txt
)
)
)

答案 1 :(得分:1)

我认为这会做你想要的。这不是一个单行,我相信它可以简化。不过,我更担心得到一些功能。

我也测试了你的用例。当它直接跟随'aaa aaa'线时,这将只替换'bbb bbb'线。具有该行的文件中的所有其他位置都不会被覆盖。

只需修改顶部的变量以及您的测试信息。

我一直以为你会:

  1. 只处理.txt文件
  2. 查询/替换整行数据
#script variables
$filePath     = 'C:\Temp\SO\'
$processFiles = Get-ChildItem -Exclude *.bak -Filter *.txt -Recurse -Path $filePath

$query        = 'aaa aaa'
$query2       = 'bbb bbb'
$replace      = 'ccc'

#script begin
foreach ( $file in $processFiles ) {
    #Pre-Processing | backup the file for archival
    $file | Copy-Item -Destination "$file.bak"

    $arrayData = Get-Content $file
    for ($i=0; $i -lt $arrayData.Count; $i++)
    {
        if ( $arrayData[$i] -match $query ) {
            if ( $arrayData[$i+1] -match $query2 ) {
                $arrayData[$i+1] = $arrayData[$i+1].Replace($query2,$replace)
            }
            else {
                #Catch if the second query isn't matched.
            }
        }
        else {
            #Catch if the first query isn't matched.
        }
    }

    #Overwrites the original text file that was being processed
    $arrayData | Out-File $file -Force
}

答案 2 :(得分:0)

这是一个单线解决方案:

$a="aaa aaa";$b="bbb bbb";$c="ccc";ls *.txt -File -Recurse|foreach{$l=0;cp $_ "$($_).bak";(cat $_)|foreach{if($_ -match $a){$l=1;$_}else{if($_ -match $b){if($l -eq 1){$_ -replace($b,$c)}else{$_};$l=2}else{$l=0;$_}}}|sc($_) -Force}

这有点模糊,我不会称之为“整洁”,但它确实有效。