paul123
Goto Top

txt Datei Werte vergleichen und neue .txt Datei erstellen

Hallo,

ich habe leider keinerlei Ahnung deswegen meine Frage hier:

Ich benötige eine Batchdatei(Windows) die es mir ermöglicht eine .txt Datei nach genau 2 Zahlen in feststehenden Zeilen zu durchsuchen und zu vergleichen.

Wenn diese Zahlen beide den gleichen Wert haben soll gar nichts passsieren.

Wenn die beiden Zahlen voneinander abweichen, soll in dem Protrokoll weiter nach der Zeile gesucht werden in der "Warnung" steht. Diese Zeile soll dann in eine neue .txt Datei geschrieben werden.

Beispiel.

Datei.txt:

Anzahl roter Autos: 1
Anzahl blauer Autos: 2

"Warnung, es wurde ein blaues Auto mehr gesehen."


-> Diese Warnung soll dann in einer neuen Error.txt ausgegeben werden.


Wie kann ich das einfach und schnell umsetzen?

Vielen Dank für die Hilfe!

Content-ID: 663171

Url: https://administrator.de/contentid/663171

Ausgedruckt am: 24.11.2024 um 00:11 Uhr

TK1987
TK1987 15.03.2021 aktualisiert um 13:23:33 Uhr
Goto Top
Moin,

eigentlich macht man sowas heute mit Powershell:
$Datei = Get-Content "Datei.txt"  
[int]$rot  = ($Datei -match '^Anzahl roter Autos') -replace '.*\D(?=\d+$)'  
[int]$blau = ($Datei -match '^Anzahl blauer Autos') -replace '.*\D(?=\d+$)'  
if ($rot -ne $blau) {$Datei -match '^Warnung' | set-content Error.txt}  

Falls es doch unbedingt Batch sein muss:
@echo off
SetLocal EnableDelayedExpansion

for /f "Tokens=1,* Delims=:" %%A in (Datei.txt) do (  
  if "%%A" equ "Anzahl roter Autos" set rot=%%B  
  if "%%A" equ "Anzahl blauer Autos" set blau=%%B  
  set Line=%%A
  if "!Line:~0,7!" equ "Warnung" set Warnung=%%A  
)

if %rot% neq %blau% echo %Warnung% > Error.txt

Gruß Thomas
GarfieldBonn
GarfieldBonn 15.03.2021 aktualisiert um 13:52:20 Uhr
Goto Top
Function Comparecars{

  [CmdLetBinding()]
  param(
    [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
    [String]$InputDatei,

    [Parameter(Mandatory = $true, Position = 1, ValueFromPipeline = $true)]
    [String]$Fehlerdatei 
  )

   # lösche alte Fehlerdatei
   if (Test-Path -Path $Fehlerdatei) {
      rm $Fehlerdatei
   }

   If (!(Test-path -Path $Inputdatei)) {
     "Eingabedatei fehlt!" | out-file -FilePath $Fehlerdatei -NoClobber -Append  
     exit # vorzeitiger Ausgang
   }
 
   # Lese Zeile 1 und 2 der Daten
   $DatInhalt = (Get-Content -path "$InputDatei")[0 .. 1]  

   $Zeile1    = $DatInhalt.Split(":")  
   $Zeile2    = $DatInhalt[1].Split(":")  

   # Stelle die Differenz der Produktion fest
   $diff      = $Zeile1[1] - $Zeile2[1]

   # Gebe Differenzen aus
   if ($diff -ne 0) {
     if ($diff -gt 0) {
       "Überschuß "+$Zeile1+": "+$diff | out-file -FilePath $Fehlerdatei -NoClobber -Append     
     } else {
       $Diff = $Diff *-1
       "Überschuß "+$Zeile2+": "+$diff | out-file -FilePath $Fehlerdatei -NoClobber -Append  
     }
   } 
}



# Aufruf der Function
Comparecars "C:\TEMP\Pseudodaten\prod.txt" "C:\TEMP\Pseudodaten\Error.txt"  
Paul123
Paul123 15.03.2021 um 16:01:24 Uhr
Goto Top
Hallo Thomas,

vielen Dank für deine Antwort!

Trotzdem brauche ich nochmal eine kurze Erklärung

$Datei = Get-Content "Datei.txt" -> Hier wird meine .txt-Datei als Variable festgelegt.
[int]$rot = ($Datei -match '^Anzahl roter Autos') -replace '.*\D(?=\d+$)' -> Hier wird die Variable rot festgelegt.
[int]$blau = ($Datei -match '^Anzahl blauer Autos') -replace '.*\D(?=\d+$)' -> Hier wird die Variable blau festgelegt.
if ($rot -ne $blau) {$Datei -match '^Warnung' | set-content Error.txt} -> Hier werden beide Variablen verglichen und wenn $rot nicht gleich $blau ist sucht er in der .txt-Datei eine Zeile die mit "Warnung" beginnt und schreibt es dann in die Error.txt

Ich verstehe aber nicht was hinter "'^Anzahl blauer Autos') passiert.

Könntest du mir diesen Teil " -replace '.*\D(?=\d+$)'" nochmal bitte erläutern.

du hast mir aber schonmal sehr geholfen!
Paul123
Paul123 15.03.2021 um 16:03:02 Uhr
Goto Top
Hallo Garfield,

das sieht kompliziert aus, vielen Dank für deine Rückmeldung.

Leider steige ich hier gar nicht durch und die Antwort von Thomas scheint hier doch etwas effektiver zu sein.

Ich danke dir trotzdem für die schnelle Reaktion!
Paul123
Paul123 15.03.2021 um 16:21:39 Uhr
Goto Top
PS:

Ich habe es ausprobiert und es hat mit der Powershell nicht funktioniert. Muss ich dazu die Datei noch modifizieren oder sollte ich das eigentlich 1:1 übernehmen können?

Die Dateien liegen beide im selben Ordner.
TK1987
TK1987 15.03.2021 um 16:49:28 Uhr
Goto Top
Zitat von @Paul123:
Ich verstehe aber nicht was hinter "'^Anzahl blauer Autos') passiert.

Könntest du mir diesen Teil " -replace '.*\D(?=\d+$)'" nochmal bitte erläutern.
Hier werden die Zeilen über Reguläre Ausdrücke ersetzt, sodass nur die hinteren Zahlen übrig bleiben.

Um das im einzelnen zu verstehen:
Regex Tutorial
und Quasi als Legende:
Regex Cheat Sheet
TK1987
Lösung TK1987 16.03.2021 um 07:16:50 Uhr
Goto Top
Zitat von @Paul123:
Muss ich dazu die Datei noch modifizieren oder sollte ich das eigentlich 1:1 übernehmen können?

Die Dateien liegen beide im selben Ordner.
Nein, dass Skript kann so 1:1 übernommen werden. Nur wenn die Dateien nicht im selben Ordner lägen, müsstest du den Dateinamen in der 1. Zeile zu einem vollständigen Pfad erweitern.

Wie genau hast du das denn mit Powershell gemacht? Am einfachsten geht es folgendermaßen:

1) Datei als .ps1-Datei abspeichern.
2) Von der Datei eine Verknüpfung machen (Rechtsklick > kopieren und dann Rechtsklick > Verknüpfung einfügen)
3) In den Verknüpfungseigenschaften sollte bei "Verknüpfungsziel" bereits der Pfad zum ps1-Skript stehen. Vor diesem musst du noch powershell -EP ByPass -File ergänzen. Vollständig sollte die Zeile dann so aussehen:
powershell -EP ByPass -File "C:\Pfad\zum\Skript.ps1"

Ausführen tust du dann immer die Verknüpfung.
Paul123
Paul123 16.03.2021 um 10:08:31 Uhr
Goto Top
Hallo Thomas,

vielen Dank schonmal.

Ich habe dir mal ein Bikld angehängt um dir zu zeigen was das Problem zu sein scheint.

Die Variablen $rot und $blau bleiben immer 0. Normalerweise müsste er doch die Zahl die da hinter steht übernehmen oder habe ich einen Denkfehler?
bild_2021-03-16_100825
TK1987
Lösung TK1987 16.03.2021 aktualisiert um 10:58:49 Uhr
Goto Top
Funktioniert hier problemlos. Stehen die Zahlen denn komplett am Zeilenende oder folgen darauf noch Leerzeichen?
Könnte auch mit der Textcodierung zusammen hängen. Welchen Ihnalt gibt er für die Variable $Datei aus?

Das "echo" kannst du bei Powershell übrigens weglassen. Einfach nur:
$Datei

Wenn die Zahlen immer in Zeile 1 und 2 stehen, ginge auch folgendes:
$Datei = Get-Content "Dok.txt"  
[int]$zuLöschen = $Datei.Split(':')[1]  
[int]gelöscht   = $Datei[1].Split(':')[1]  

if ($zuLöschen -ne $gelöscht) {$Datei -match '^Warnung' | Set-Content Error.txt}  
$Datei liefert von der Variable Datei die Zeile mit dem Index 0 (der Index ist eine Nummerierung, beginnend bei 0). Diese wird beim Doppelpunkt in zwei Teile gesplittet und davon der Zweite Teil (also Index 1) in der Variable $zuLöschen gespeichert.
Das Selbe wird der 2. Zeile der Datei gemacht, anschließend müssen nur noch die Zahlen verglichen werden.
Paul123
Paul123 16.03.2021 um 11:10:55 Uhr
Goto Top
Nein die stehen nicht immer in der 1. und 2. Zeile.


Es funktioniert jetzt aber und das Problem ist das ö und das ä. Diese werden nicht richtig aufgelöst. Die .txt-Datei ist im UTF-8 Format.

Wenn ich oe und ae eingebe funktioniert es.

Gibt es eine Möglichkeit das zu beheben ohne dass ich oe und ae verwenden muss?
TK1987
Lösung TK1987 16.03.2021 aktualisiert um 11:16:10 Uhr
Goto Top
Zitat von @Paul123:
Gibt es eine Möglichkeit das zu beheben
Ja. Ändere einfach Zeile 1 wie folgt ab:
$Datei = Get-Content -Encoding utf8 "Dok.txt"  
Dann machen auch die Umlaute kein Problem mehr.
Paul123
Paul123 16.03.2021 aktualisiert um 11:17:33 Uhr
Goto Top
Achso und noch 2 Dinge. In deinem Script sucht er ja nach dem Wort "Warnung" am Anfang einer Zeile (^). Das Wort Warnung steht allerdings mitten in der Zeile trotzdem soll er mir genau diese Zeile komplett in die Error.txt-Datei schreiben.

Desweiteren steht eigentlich vor "Anzahl zu löschender Datensätze:" noch eine # also genau so:

"# Anzahl zu löschender Datensätze"

füge ich die Raute mit in das Script ein gibt es wieder einen Fehler. Bei Linux muss in so einem Fall die Variablenbedingung anders geschrieben werden damit er weiß, dass die Raute zum Text gehört den er suchen soll. Ist das hier auch der Fall?
Paul123
Paul123 16.03.2021 um 11:19:32 Uhr
Goto Top
Das mit der Raute habe ich selber geklärt! Sorry für mein Unwissen. Ich bin dir sehr Dankbar für deine Hilfe
TK1987
Lösung TK1987 16.03.2021 aktualisiert um 11:29:50 Uhr
Goto Top
Zitat von @Paul123:
Achso und noch 2 Dinge. In deinem Script sucht er ja nach dem Wort "Warnung" am Anfang einer Zeile (^).
richtig.
Das Wort Warnung steht allerdings mitten in der Zeile trotzdem soll er mir genau diese Zeile komplett in die Error.txt-Datei schreiben.
Du kannst das Zirkumflex für den Zeilenanfang natürlich einfach weglassen - dann findet er die Warnung auch, wenn sie mitten in der Zeile steht. Solange das Wort Warnung nur einmal vorkommt kein Problem, falls nicht musst du halt eine andere Lösung finden, wie du die Zeile eindeutig indentifizieren kannst.
Paul123
Paul123 16.03.2021 aktualisiert um 11:39:16 Uhr
Goto Top
Get-Content : Es wurde kein Positionsparameter gefunden, der das Argument "Dok.txt" akzeptiert.  
In C:\Users\Paul Liegmann\Desktop\Neuer Ordner (2)\Test.ps1:1 Zeichen:10
+ $Datei = Get-Content "Dok.txt" -Encoding UTF8 "Dok.txt"  
+          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-Content], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetContentCommand
 
Der Wert "False" kann nicht in den Typ "System.Int32" konvertiert werden. Fehler: "Die Eingabezeichenfolge hat das   
falsche Format."  
In C:\Users\Paul Liegmann\Desktop\Neuer Ordner (2)\Test.ps1:2 Zeichen:1
+ [int]$rot  = ($Datei -match '^# Anzahl zu löschender Datensätze: ')[0 ...  
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException
 
Der Wert "False" kann nicht in den Typ "System.Int32" konvertiert werden. Fehler: "Die Eingabezeichenfolge hat das   
falsche Format."  
In C:\Users\Paul Liegmann\Desktop\Neuer Ordner (2)\Test.ps1:3 Zeichen:1
+ [int]$blau  = ($Datei -match '^# Anzahl gelöschter Datensätze: ')  ...  
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) , ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException"  


Das ist die Fehlermeldung die ich bekomme wenn ich -Encoding utf8 "Dok.txt" noch mit anfüge.
TK1987
Lösung TK1987 16.03.2021 aktualisiert um 11:42:32 Uhr
Goto Top
Zitat von @Paul123:
Get-Content : Es wurde kein Positionsparameter gefunden, der das Argument "Dok.txt" akzeptiert.  
In C:\Users\Paul Liegmann\Desktop\Neuer Ordner (2)\Test.ps1:1 Zeichen:10
+ $Datei = Get-Content "Dok.txt" -Encoding UTF8 "Dok.txt"  
+          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Du hast "Dok.txt" doppelt in der Zeile. Einmal weglöschen dann läufts.
Paul123
Paul123 16.03.2021 um 11:47:10 Uhr
Goto Top
Das wars. Ich danke dir!!!

Ich entlasse dich dann erstmal und bedanke mich für deine Hilfe. Das bringt mich ein großes Stück weiter.

Falls ich nochmal eien Frage haben sollte würde es mich freuen nochmal von dir zu hören!

Vielen Dank

Paul
TK1987
Lösung TK1987 16.03.2021 um 11:47:51 Uhr
Goto Top
Immer gerne.
Paul123
Paul123 17.03.2021 um 13:08:49 Uhr
Goto Top
Hallo Thomas,

zu meinem Thema habe ich noch eine Frage.

Die .txt-Datei die ausgelesen werden soll liegt in einem Ordner wo jeden Tag eine .txt-Datei hingeschrieben wird. Die Dateien unterscheiden sich nur durch einen Zeitstempel.

Beispiel:

Datei_20210316
Datei_20210317

es wird jeden Tag nur eine einzige Datei geschrieben und das Script soll auch jeden Tag nur einmal laufen.

Gibt es eine Möglichkeit dem Script zu sagen, dass er sich nur die Datei mit dem aktuellem Datum angucken soll?

VG

Paul
GarfieldBonn
GarfieldBonn 17.03.2021 um 14:49:38 Uhr
Goto Top
$Datei=Get-content ("Datei_"+(get-date).ToString(‘yyyyMMdd’)+".txt") -Encoding UTF8
Paul123
Paul123 23.03.2021 um 10:35:19 Uhr
Goto Top
Super vielen Dank.

Eine letzte Frage noch zu dem Thema:


Die Datei wird immer mit einer Uhrzeit ausgegeben.

Bedeutet:

Datei_20210323_180504345 Name+Datum+Uhrzeit

-> Den letzten Teil (Uhrzeit) Will ich bei meiner Suche nicht berücksichtigen. Was muss ich also hier ergänzen:

$Datei=Get-content ("Datei_"+(get-date).ToString(‘yyyyMMdd’)+".txt") -Encoding UTF8  
TK1987
TK1987 23.03.2021 aktualisiert um 10:59:06 Uhr
Goto Top
Moin,

Zitat von @Paul123:
Die Datei wird immer mit einer Uhrzeit ausgegeben.
-> Den letzten Teil (Uhrzeit) Will ich bei meiner Suche nicht berücksichtigen. Was muss ich also hier ergänzen:

$Datei=Get-content ("Datei_"+(get-date).ToString(‘yyyyMMdd’)+".txt") -Encoding UTF8  
Sofern immer nur eine Datei / Tag erstellt wird, könntest du einfach einen Wildcard vor die Erweiterung setzen
$Datei=Get-content ("Datei_"+(get-date).ToString(‘yyyyMMdd’)+"*.txt") -Encoding UTF8  

Gruß Thomas
Paul123
Paul123 30.03.2021 um 11:04:33 Uhr
Goto Top
Hat funktioniert danke.


Wenn die Datei selber nicht im gleichen Ordner liegt und ich einen Pfad angeben will bekomme ich nur eine Fehlermeldung

Was mache ich hier falsch?
$Datei=Get-content -Path C:\Temp\("Datei_Name_"+(get-date).ToString(‘yyyyMMdd’)+"*.txt") -Encoding String  


Ich glaube ich habe da nur ein Problem mit der Syntax.

Wäre schön wenn du mir da nochmal kurz helfen könntest. Für dich bestimmt nur eine Antwortzeile, vielen Dank schonmal.
TK1987
TK1987 30.03.2021 aktualisiert um 12:49:27 Uhr
Goto Top
Zitat von @Paul123:
Was mache ich hier falsch?
$Datei=Get-content -Path C:\Temp\("Datei_Name_"+(get-date).ToString(‘yyyyMMdd’)+"*.txt") -Encoding String  
Das Path-Argument muss als zusammenhängende Zeichenkette übergeben werden
$Datei=Get-content -Path ("C:\Temp\Datei_Name_"+(get-date).ToString('yyyyMMdd')+"*.txt") -Encoding utf8