Textdatein in Unterordnern suchen und texte ersetzen per powershell?

2 Antworten

die ordner die einen sehr langen namen haben da geht es nicht 

Für lange Pfade bist Du selbst verantwortlich, das hat nichts mit Powershell zu tun.

theoretisch könntest Du mit 8.3- Namen arbeiten, das ist jedoch unter Powershell nicht mehr vorgesen . Solche KurzNamen sind ein Relikt aus Dos-Zeiten und nicht mehr auf jedem Rechner verfügbar. Du kannst versuchen mit hilfe der alten VisualbasicScript-Bibliotken den evtl. vorhandenen Kurzpfad zu ermitteln und damit zu arbeiten.

$fso = New-Object -ComObject Scripting.FileSystemObject

Get-ChildItem -Path 'c:\Testpfad' -Recurse -Filter "*.txt" |
  ForEach-Object { 
    $shortPath =$fso.getfile($_.fullname).ShortPath  #ermittle  8.3-Pfad
    Write-Host "$($_.FullName)  =>  $shortPath"  -fo green
     # Powershells  -replace-Operator verwendet ReguläreAusdrücke darum für statische Ersetzungen besser die .Replace()-Methode verwenden...  
    (Get-Content $shortPath -RAW).Replace('test@test.com','replaced@test.com')|
      Set-Content $shortPath
  }

..ansonsten bleibt dir nur die Umstellung des Systems auf lange Pfade. (Admin erforderlich!)

New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force

Dann geht der Klassiker fehlerfrei.

Get-ChildItem -Path 'c:\basispfad' -Recurse -Filter "*.txt" |
  ForEach-Object { 
    (Get-Content $_.FullName -RAW).Replace('test@test.com','replaced@test.com')|
      Set-Content $_.FullName
  }
Woher ich das weiß:eigene Erfahrung – Ich mach das seit 30 Jahren
derendgegner911 
Fragesteller
 11.10.2023, 11:37

habe alle ordner umbenannt , nun geht es aber sehr langsam arbeitet er alles ab ,glaube brauche 2 tage bei der geschwindigkeit .. kann man das beschleunigen ?

0
Erzesel  11.10.2023, 15:34
@derendgegner911

Keine Ahnung wie groß die Dateien sind auch so sind über 1000 eine ziemliche Hausnummer. ...und es ist unvermeidlich, das die Dateien in den speicher geladen werden und nach dem Begriff zum austauschen durchsucht werden ...und natürlich wieder zurückgeschrieben werden...

etwas schneller geht es, wenn man die Liste der ermittelten Textdateien auf mehrere Jobs verteilt und das Durchsuchen der Dateien (Replace) den Workern der Jobs überlässt.

function Get-PartSizes ( [Long]$Size , [Long]$Parts ) {
    $Quotient=[Math]::Floor($Size/$parts)
    $Remainder=$Size%$parts
    $(for ($i=0;$i -lt $parts; ++$i){
        if ($Remainder){
            $Quotient+1
            --$Remainder
        }
        else{$Quotient}
    })|? {$_}
}


 #was die Jobs  tun sollen (das  gleiche  wie   im oberen  Script)
$Job_Worker = {
    param(
        [Array]$FileList=@()
    )
    $FileList |
        ForEach-Object { 
            "verarbeite Datei $_" #nur mal ein Lebenszeichen des Jobs aus  dem Hintergrund
           try {  #leere dateien abfangen "Nichts"  kann keine Methode .Replace()   besitzen
               (Get-Content $_ -RAW).Replace('test@test.com','replaced@test.com')|
               Set-Content $_ 
           }
           catch {"File seams empty"} 
        }
}


 #Anzahl der parallelen  Jobs festlegen  (Hier Automatisch,  kanst  aber  eine  Dir  genehme  Zahl  festlegen) 
$JobCount=$env:NUMBER_OF_PROCESSORS

  #Liste  aller .txt -Dateien
[Array]$SearchFiles =(Get-ChildItem -Path 'c:\basepath' -Filter *.txt -Recurse -ea Silent).FullName

 #Dateiliste in einigermaßen gleich große Teile zerlegen
$ListSlices=Get-PartSizes $SearchFiles.Count $JobCount |
    ?{$_}|
    %{$base=0}{
        ,$SearchFiles[$base..($base+$_-1)]  #aufpassen, Comma-Operator ...als neues Array übergeben
        $base+=$_
    }

  #Jobs  starten
$Jobs = $ListSlices|
    %{ Start-Job  -ScriptBlock $Job_Worker  -ArgumentList (,$_) }


#$Jobs
 #auf vollzug  warten
$Jobs| Receive-Job -wait
pause

Nicht wundern, das verteilen der Dateien auf die einzelnen Jobs und deren Initialisierung nimmt etwas Zeit in Anspruch. einmal im Gang machen 10..20 parallele Verarbeitungseinheiten jedoch ordentlich Dampf

0
derendgegner911 
Fragesteller
 11.10.2023, 15:40
@Erzesel

Mir würde es auch Reichen wenn einfach von allen txt Dateien die ersten 20 Zeilen gelöscht werden , wäre das einfacher umsetzbar?

0
Erzesel  11.10.2023, 15:44
@derendgegner911

sind das normal windws-Textdateien oder welche die unter Linux/Apple erstellt wurden?

0
Erzesel  11.10.2023, 16:05
@derendgegner911
Get-ChildItem -Path 'C:\basepath' -Filter '*.txt' -Recurse -ea sil|
 %{
   $NewText = Get-Content $_.FullName|
    Select-Object -Skip 20
   $NewText|
    Set-Content $_.FullName
 }

...aber aufgepasst, die Routine schneidet gnadenlos bei allen .txt.Dateien die ersten 20 Zeilen ab! Kürzere datein werden geleert.

0
derendgegner911 
Fragesteller
 11.10.2023, 16:06
@Erzesel

Sind alle Dateien gleich in den ersten 20 Zeilen ist wie so eine Art FAQ und der soll weg ,teste es gleich Mal aus , und der sucht dann auch die Unterordner ab ?

0

find . -type f -name "*.txt" -exec sed -i '' 's/alte@email.com/neue@email.com/g' {} +

Dieser Befehl durchsucht alle Textdateien in den Unterordnern auf deinem Desktop und ersetzt alte@email.com durch neue@email.com. Stelle sicher, dass du vorher eine Sicherungskopie deiner Daten hast, falls etwas schiefgeht.

derendgegner911 
Fragesteller
 11.10.2023, 02:25

find : Datei *.txt nicht gefunden

In Zeile:1 Zeichen:1

+ find . -type f -name "*.txt" -exec sed -i '' 's

0
MipiPann  11.10.2023, 02:30
@derendgegner911

Get-ChildItem -Path "C:\Pfad\Zum\Ordner" -Recurse -Filter "*.txt" | ForEach-Object {

  (Get-Content $_.FullName) | ForEach-Object {

    $_ -replace "alte@email.com", "neue@email.com"

  } | Set-Content $_.FullName

}

Sowas in die Richtung kann das funktionieren?

0
derendgegner911 
Fragesteller
 11.10.2023, 02:44
@MipiPann

das klappt , aber die ordner die einen sehr langen namen haben da geht es nicht da kommt dann immer ein fehler ,ordner mit einem kurzen namen klappt es perfekt

1
MipiPann  11.10.2023, 02:46
@derendgegner911

Dort geht es nicht weil Sonderzeichen drinnen vorkommen denke ich, die müsstest du das Script etwas anpassen, so eventuell:

Get-ChildItem -Path "C:\Pfad\Zum\Ordner" -File -Recurse -Filter "*.txt" | ForEach-Object {

  $newPath = [System.IO.Path]::Combine($_.DirectoryName, [System.IO.Path]::GetRandomFileName())

  Move-Item $_.FullName $newPath

  (Get-Content $newPath) | ForEach-Object {

    $_ -replace "alte@email.com", "neue@email.com"

  } | Set-Content $_.FullName

  Move-Item $newPath $_.FullName

}

0
Erzesel  11.10.2023, 09:43
@MipiPann
 -replace "alte@email.com", "neue@email.com"

Dir ist schon klar, das der -replace-operator mit einer RegEx-suche arbeitet und den Punkt als "anyCharacter" wertet?

der Punkt in einem suchausdruck sollte deshalb escaped werden! :

$string -replace "alte@email\.com", "neue@email.com"
Hast du WSL aktiv?

wer braucht WSL (Windows-Subsystem für Linux), wenn er Powershell kann?

echt mal... das löst übrigens auch nicht das Problem der Langen Pfade...

0
derendgegner911 
Fragesteller
 11.10.2023, 12:00
@Erzesel

hi alles klappt nun aber sehr sehr langsam arbeitet er alles ab ,kann man das beschleunigen irgendwie ?

0
MipiPann  11.10.2023, 12:15
@Erzesel

Im Normalfall nutze ich kein Windows, aber meine Lösung scheint zu funktionieren, ergo ich bin ein Genie

0
derendgegner911 
Fragesteller
 11.10.2023, 15:29
@MipiPann

es gibt ja noch den befehl

Foreach-ObjectFast

aber leider funktioniert der bei mir in powershell nicht, es ist extrem lahm das abarbeiten der datein,hat jemand ne lösung

0