Benutzer mit den meisten Antworten
Suchbegriffe aus Textdatei auf Textdateien anwenden und Treffer in neue Textdatei schreiben

Frage
-
Hallo Zusammen,
ich habe das folgende Problem:
In einer Textdatei gibt es 4000 Suchebgriffe, diese sollen nun auf etwa 50.000 Textdateien angewandt werden. Sollte ein Suchbegriff in einer Textdatei auftauchen, sollen die Namen der entsprechenden Dokumente zunächst in eine separate Textdatei geschrieben werden, die wiederrum den Suchbegriff als Namen trägt. Ich hoffe dass das ganze mit Powershell einigermaßen performant abläuft. Ein entsprechendes Batch-Skript ist leider zu langsam.
Bislang bin ich zu dem folgenden Code gekommen:
foreach($mail in "mails.txt") { Get-ChildItem -recurse -include *.eml | Select-String -SimpleMatch $mail > "$mail.txt" }
Leider funktioniert das ganze nicht sehr gut. Die zu durchsuchenden Dateien befinden sich in 3 Unterordnern, daher die rekursive Abfrage. Ich brauche nur den Dateinamen des Suchtreffers, da in einem weiteren Schritt diese Dateien als PDF gedruckt werden sollen.
Das erste problem scheint schon, dass ich mit der ersten Schleife gar nicht alle einzelnen Suchwörter (Zeilen) in die Variable bekomme.
Wäre sehr nett wenn ihr mich etwas unterstützen könntet!
danke!
Antworten
-
Also es scheint tatsächlich ein Problem mit dem Dateinamen zu sein, da er ein paar Mails ordentlich durchläuft und dann bei folgendem Aufbau Probleme hat:
100205-20141218-Cron _root@a19s09_ [ -x _usr_.eml
Das problem scheint die eckige Klammer zu sein. Gibt es da eine Lösung, außer die aus allen Dateinamen zu entfernen :-)
€: Ich habe das Problem jetzt gelöst. Eckige Klammern sind als Platzhalter in Powershell definiert. Wenn man mit variablen Dateinamen arbeitet, sollte man den Paramter -LiteralPath nehmen, dann funktioniert alles.
Der Code ist jetzt etwas gekürzt und sieht wie folgt aus:
# Suchbegriffe und einzelne Mails laden $begriffe = Get-Content mails.txt $mails = Get-ChildItem '.\' -Include *.eml -Recurse #äußere Schleife arbeitet alle Suchbegriffe ab Foreach ($begriff in $begriffe){ #innere Schleife wendet Suchbegriff auf Mail an Foreach($mail in $mails){ #abgleich, ob suchwort in datei vorhanden ist if(Get-Content -LiteralPath $mail | select-string -SimpleMatch $begriff){ echo $mail.Name >> $begriff.txt } } }
Ich könnte das ganze aber eigentlich noch beschleunigen, denn im Prinzip muss man ja nur im Adressbereich des E-Mail-Header nach Mails suchen. D.h., sobald der String "content-type" oder ähnliches kommt, könnte die suche im Text abgebrochen werden, da die Mail dann sicherlich nicht mehr enthalten ist. Kann man das irgendwie sinnvoll implementieren?
- Bearbeitet iof89wu4r89m Dienstag, 21. Juli 2015 08:47
- Als Antwort markiert Denniver ReiningMVP, Moderator Mittwoch, 29. Juli 2015 12:26
Alle Antworten
-
Also ich hab meinen Code jetzt überarbeitet und gehe wie folgt vor:
Get-Content mails.txt | Foreach-Object ($_){ New-Item .\$_.txt -type file Get-ChildItem -recurse -include *.eml | Select-String -Simplematch $_ >> $_.txt Write-Output ------- }
Jetzt klappt zumindest, dass jeder Suchbegriff einzeln aus der Textdatei gelesen wird. Es wird ein gleichnamiges File angelegt. Nur funktioniert das Zuweisen zu dieser datei leider überhaupt nicht. Gebe ich statt der Variablen feste Werte ein klappt es wunderbar. Ist die Zuweisung >> §_.txt evtl. nicht korrekt? -
Hi,
ich hoffe, dass ich das richtig verstanden habe - hier mein Ansatz:
function Get-EmailSuche { # suchwörter und mails laden $AlleSuchwoerter = Get-Content 'C:\temp\technet-mails\mails.txt' $AlleMails = Get-ChildItem 'C:\temp\technet-mails' -Include *.eml -Recurse # für jede mail in den ordnern foreach ($Mail in $AlleMails){ # mailinhalt in var laden $MailInhalt = Get-Content $Mail # für jedes suchwort in der suchwortliste foreach ($Suchwort in $AlleSuchwoerter){ # wenn das suchwort im mailcontent gefunden wird - name ausgeben if ($MailInhalt | Select-String -SimpleMatch $Suchwort){ # $Mail.Name ist nur der Dateiname # $Mail.FullName ist der komplette Dateipfad mit Dateiname # $Mail.Name $Mail.FullName } } } } $temp = Get-EmailSuche $temp | Out-File 'C:\temp\technet-mails\Report.txt'
Die große Frage ist nun, wie performant das ist. Diese function geht jetzt eine email zur zeit durch, aber man könnte das auch mit verschiedenen mitteln parallelisieren. Schau erstmal wie das hier läuft.
Gruß,
-
Hallo Alexander,
danke für den Code, dass sieht echt gut aus.
Ich habe das etwas angepasst (erst Suchbegriffe, dann Mails als Schleife, damit man fertige Suchbegriffe schon verwenden kann), allerdings erhalte ich immer den folgenden Fehler
Get-Content : Die dynamischen Parameter für das Cmdlet können nicht abgerufen werden. Das angegebenePlatzhalterzeichenmuster ist ungültig:
Dann folgt der Dateiname der E-mail. Und danach:
+ $inhalt = get-Content $mail
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Content], ParameterBindingException
Ich habe auch schon mit absolutem Pfad bei der Zuweisung ($mails=) gearbeitet, das brachte jedoch keine Verbesserung.
# Suchbegriffe und einzelne Mails laden $begriffe = Get-Content mails.txt $mails = Get-ChildItem '.\' -Include *.eml -Recurse #äußere Schleife arbeitet alle Suchbegriffe ab Foreach ($begriff in $begriffe){ Clear-Variable $treffer #innere Schleife wendet Suchbegriff auf Mail an Foreach($mail in $mails){ #Dateiinhalt in variable laden $inhalt = get-Content $mail #abgleich, ob suchwort in datei vorhanden ist if($inhalt | select-string -SimpleMatch $begriff){ $treffer = $mail.Name } } if($treffer) { get-content $treffer > $begriff.txt } }
-
Schon mal durch debuggt (z.B.) mit dem ISE? Ist in $mails zur Fehlerzeit was drin und wenn ja was?
Mal $mail.FullName ausgeben lassen und prüfen bitte.
Ich kann den Fehler nicht im Geringsten nachstellen.
Machst du das auf Dateiebene lokal oder wo?
LG
-
Also es scheint tatsächlich ein Problem mit dem Dateinamen zu sein, da er ein paar Mails ordentlich durchläuft und dann bei folgendem Aufbau Probleme hat:
100205-20141218-Cron _root@a19s09_ [ -x _usr_.eml
Das problem scheint die eckige Klammer zu sein. Gibt es da eine Lösung, außer die aus allen Dateinamen zu entfernen :-)
€: Ich habe das Problem jetzt gelöst. Eckige Klammern sind als Platzhalter in Powershell definiert. Wenn man mit variablen Dateinamen arbeitet, sollte man den Paramter -LiteralPath nehmen, dann funktioniert alles.
Der Code ist jetzt etwas gekürzt und sieht wie folgt aus:
# Suchbegriffe und einzelne Mails laden $begriffe = Get-Content mails.txt $mails = Get-ChildItem '.\' -Include *.eml -Recurse #äußere Schleife arbeitet alle Suchbegriffe ab Foreach ($begriff in $begriffe){ #innere Schleife wendet Suchbegriff auf Mail an Foreach($mail in $mails){ #abgleich, ob suchwort in datei vorhanden ist if(Get-Content -LiteralPath $mail | select-string -SimpleMatch $begriff){ echo $mail.Name >> $begriff.txt } } }
Ich könnte das ganze aber eigentlich noch beschleunigen, denn im Prinzip muss man ja nur im Adressbereich des E-Mail-Header nach Mails suchen. D.h., sobald der String "content-type" oder ähnliches kommt, könnte die suche im Text abgebrochen werden, da die Mail dann sicherlich nicht mehr enthalten ist. Kann man das irgendwie sinnvoll implementieren?
- Bearbeitet iof89wu4r89m Dienstag, 21. Juli 2015 08:47
- Als Antwort markiert Denniver ReiningMVP, Moderator Mittwoch, 29. Juli 2015 12:26
-
Ich habe das ganze jetzt noch so gestaltet, dass die Mails im Trefferfall verschoben werden. Das führt natürlich dazu, dass beim nächsten Durchlauf mit dem nächsten Begriff die entsprechende Mail nicht mehr da ist und ich eine Fehlermeldung erhalte. Kann man denn eine Variable "$mail" aus "$mails" löschen, sodass diese nicht mehr enthalten ist?
Ein neuladen von Mails ist nicht sehr performant, da dass ganze auf etwa 80.000 Objekte angewandt wird...
-
Hey, vielleicht hilft es dir ja noch, auch wenn die letzte Antwort schon etwas her ist.
Schreib doch einfach den ganzen inneren Block in eine Try-Catch-Umgebung. Also etwa so:
# Suchbegriffe und einzelne Mails laden $begriffe = Get-Content mails.txt $mails = Get-ChildItem '.\' -Include *.eml -Recurse #äußere Schleife arbeitet alle Suchbegriffe ab Foreach ($begriff in $begriffe){ #innere Schleife wendet Suchbegriff auf Mail an Foreach($mail in $mails){ #abgleich, ob suchwort in datei vorhanden ist try{ if(Get-Content -LiteralPath $mail |select-string -SimpleMatch $begriff){ echo $mail.Name >> $begriff.txt} }catch{} } }
Falls die E-Mail nicht da ist, gibt es einen internen Fehler, der durch den (leeren) Catch-Block abgefangen wird. Du kannst auch irgendwas in dem Catch-Block machen lassen, wie z.B. eine Meldung ausgeben. Ist aber wahrscheinlich unnötig.
Viele Grüße
Christoph