2

我以前从未使用过 powershell,而且 Google 并没有给出我所需要的答案。我希望你们能帮助我。我需要找到目录(包括子目录)中包含 2 行的所有文件:

aaa aaa
bbb bbb

并将第二行替换为ccc

bbb bbb如果 line没有紧随其后,则不应发生替换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 中看到了很多简洁的单行解决方案。我的情况有类似的情况吗?谢谢

4

3 回答 3

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
)
)
)
于 2012-12-14T16:58:55.993 回答
2

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

我也测试了你的用例。这只会在直接跟随 '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
}
于 2012-12-14T19:00:24.833 回答
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}

这有点晦涩,我不会称它为“整洁”,但它确实有效。

于 2013-07-26T10:05:50.093 回答