lorus11
Goto Top

Batch - Bestimmte Zeilen aus txt auslesen und in neue txt schreiben

huhu zusammen,

ich möchte mithilfe von einem batch immer die ersten xx Zeilen und die letzten yy Zeilen auslesen und in eine neue txt schreiben.
Das Logfile quasi kürzen. Es soll immer Zeile 1 - X und Zeile Y - Ende ausgeschnitten werden.

@echo off & setlocal enabledelayedexpansion
find /n "Sicherung begonnen" test.log > rctmp.txt  
for /F "delims= skip=2 tokens=1" %%a in (rctmp.txt) do if not defined zeilex set "zeileX=%%a"  
find /n "šberprfung abgeschlossen" test.log > rctmp.txt  
for /F "delims= skip=2 tokens=1" %%a in (rctmp.txt) do set zeileY=%%a  

set /a Zeile=0
for /f "delims=" %%i in ('type test.log') do (  
	set /a Zeile+=1
	if /I !Zeile! LEQ !zeile1! (
		echo %%i
	) >> output.txt
	if /I !Zeile! GEQ !Zeile2! (
		echo %%i
	) >> output.txt
)

Den Wert für ZeileX und ZeileY finde ich im ersten Teil raus ... und im 2ten Teil erfolgt dann die Ausgabe. Allerdings hab ich folgendes Problem. In dem Logfile gibt es einige Leerzeilen. Bei meinem Ausgabeverfahren werden diese Leerzeilen allerdings nicht als Zeilen anerkannt wodurch sich die ganze Sache verkürzt bzw. die für X und Y nicht mehr stimmen.

Sprich aus

Sicherungsstatus
Vorgang: Sicherung
Aktives Sicherungsziel: 4mm DDS
Mediumname: "Band 20071115-0300"  

Volumeschattenkopie-Erstellung: Versuch 1.
Sicherung von "E: Daten"  
Sicherungssatz #1 auf Medium #1
Sicherungsbeschreibung: "Band 20071115-0300"  
Mediumname: "Band 20071115-0300"  

Sicherungsart: Normal

Sicherung begonnen am 15.11.2007 um 03:01.


wird

Sicherungsstatus
Vorgang: Sicherung
Aktives Sicherungsziel: 4mm DDS
Mediumname: "Band 20071115-0300"  
Volumeschattenkopie-Erstellung: Versuch 1.
Sicherung von "E: Daten"  
Sicherungssatz #1 auf Medium #1
Sicherungsbeschreibung: "Band 20071115-0300"  
Mediumname: "Band 20071115-0300"  
Sicherungsart: Normal
Sicherung begonnen am 15.11.2007 um 03:01.


wie bekomme ich es hin, das diese Leerzeilen korrekt mit übernommen werden?

Content-ID: 75730

Url: https://administrator.de/forum/batch-bestimmte-zeilen-aus-txt-auslesen-und-in-neue-txt-schreiben-75730.html

Ausgedruckt am: 24.12.2024 um 14:12 Uhr

58502
58502 11.12.2007 um 13:25:24 Uhr
Goto Top
Was macht den "DEQ" ? face-wink
lorus11
lorus11 11.12.2007 um 13:29:21 Uhr
Goto Top
muss natürlich GEQ heißen :D
bastla
bastla 11.12.2007, aktualisiert am 18.10.2012 um 18:32:48 Uhr
Goto Top
Hallo lorus11 und willkommen im Forum!

Dein Thema hatten wir (in ähnlicher Form) neulich hier ...

Grüße
bastla
lorus11
lorus11 12.12.2007 um 13:04:34 Uhr
Goto Top
Folgender Code bringt mir nun auch die gewünschten Leerzeilen face-smile

for /f "tokens=1* delims=:" %%i in ('findstr /n $ "%InFile%"') do if %%i leq %Zeile1% if "%%j"=="" (echo.>>"%OutFile%") else echo %%j>>"%OutFile%"  


Vielen Danke! face-smile
lorus11
lorus11 12.12.2007 um 14:12:47 Uhr
Goto Top
Hab jetzt nur das Problem, das die Ausführung von dem Batch auf ein Logfile, das 5.000 Zeilen hat, extrem Lange dauert.

Kann man da noch irgendwas optimieren?
Biber
Biber 12.12.2007 um 18:23:30 Uhr
Goto Top
Moin lorus11,

optimieren oder (was meistens ja nur gemeint ist) für performantere Verarbeitung sorgen lässt sich ja immer auf zwei Arten
  • dasselbe machen wie bisher, aber schneller (neuerer Rechner, *.exe-Datei statt Batch-Interpreter,...)
  • oder die Lösungsstrategie bzw. die Grundvoraussetzungen ändern

In der einen Batchzeile ist das einzig Schnelle natürlich die "findstr"-Verarbeitung.
Diese muss aber
  • eine Textdatei von 5000 Zeilen durchpflügen (nicht schlimm),
  • diese aber während der Verarbeitung als "virtuelle Datei" im Hauptspeicher halten (schon schlimm) und
  • alle 5000 Zeilen auf den Bildschirm ausgeben, auch wenn die wenigsten dort ankommen (ganz ganz stinkelangsam).

Wenn Du also von den 5000 Zeilen eigentlich nur die ersten x (mit x<100) und die letzten y (mit y<100) Zeilen brauchst, dann solltest Du vorher mit einem geeignetem "Findstr /v"-Befehl alle Body/Detail-Zeilen des Logfiles wegfiltern.
Irgendetwas Gemeinsames werden diese Zeilen ja haben, ein "..copied.." oder ein "c:\..."?

Wenn Du dieses Kriterium ermittelt hast, dann machen wir weiter.

Grüße
Biber
bastla
bastla 12.12.2007 um 21:12:26 Uhr
Goto Top
Hallo lorus11!

Als Kombination aus Biber's Vorschlägen, insbesondere
die Lösungsstrategie ändern
kann ich Dir ein VBScript (nicht wegen des schnelleren Interpreters face-wink, sondern wegen der erweiterten Möglichkeiten zur Textbearbeitung) vorschlagen:
Quelle = "D:\Test.log"  
Ziel = "D:\output.txt"  

BisText = "Sicherung begonnen"  
VonText = "Überprüfung abgeschlossen"  

Set fso = CreateObject("Scripting.FileSystemObject")  
LogText = Split(fso.OpenTextFile(Quelle, 1).ReadAll, vbCrLF)
LogZeilen = UBound(LogText)

BisZeile = 0
BisLen = Len(BisText)
For i = 0 To LogZeilen
	If Left(LogText(i), BisLen) = BisText Then
		BisZeile = i
		Exit For
	End If
Next

VonZeile = 0
VonLen = Len(VonText)
For i = LogZeilen To 0 Step -1
	If Left(LogText(i), VonLen) = VonText Then
		VonZeile = i
		Exit For
	End If
Next

If (BisZeile * VonZeile) Then
	Set Z = fso.OpenTextFile(Ziel, 2, True)
	For i = 0 To BisZeile
		Z.WriteLine LogText(i)
	Next

	Z.WriteLine "----------------------------------------------------------------------------"  
	Z.WriteBlankLines 3     '3 Leerzeilen erzeugen  
	Z.WriteLine "----------------------------------------------------------------------------"  

	For i = VonZeile To LogZeilen
		Z.WriteLine LogText(i)		
	Next
	Z.Close
Else
	WScript.Echo "Logdaten nicht korrekt!"  
	WScript.Quit 1
End If
Für Testzwecke sind Ein- und Ausgabedatei fest "verdrahtet", aber das lässt sich natürlich im Fall des Falles etwas benutzerfreundlicher gestalten.

"BisText" und "VonText" werden nur am Anfang der Zeile und nur in der angegebenen Schreibweise (mit Unterscheidung Groß-/Kleinschreibung) gesucht. Sollte einer der beiden Texte nicht gefunden werden, erhältst Du eine Fehlermeldung und einen Errorlevel 1.

In der Ausgabe sind zwischen den beiden Blöcken noch exemplarisch Trennlinien und Leerzeilen platziert.

Starten lässt sich das Script bei Bedarf auch aus einer Batchdatei, wobei auch eine Abfrage des Errorlevels erfolgen kann - Beispiel:

Grüße
bastla
lorus11
lorus11 13.12.2007 um 09:44:21 Uhr
Goto Top
@Biber
Wenn Du also von den 5000 Zeilen
eigentlich nur die ersten
x (mit x<100) und die letzten y (mit
y<100) Zeilen brauchst, dann solltest Du
vorher mit einem geeignetem "Findstr
/v"-Befehl alle Body/Detail-Zeilen des
Logfiles wegfiltern.
Irgendetwas Gemeinsames werden diese Zeilen
ja haben, ein "..copied.." oder ein
"c:\..."?

In dem Log kommt immer 2x Sicherung begonnen und 2x Sicherung abgeschlossen vor.
Das erste Stück soll ausgeschnitten werden von Zeile 0 - "Sicherung begonnen" (1)
Das zweite Stück wird von "Sicherung abgeschlossen" (1) - "Sicherung begonnen" (2) ausgeschnitten
Und das dritte schnitt dann von "Sicherung abgeschlossen" (2) - 6 Zeilen danach.

Das sieht dann so aus:

Sicherungsstatus
Vorgang: Sicherung
Aktives Sicherungsziel: 4mm DDS
Mediumname: "Band 20071115-0300"  

Volumeschattenkopie-Erstellung: Versuch 1.
Sicherung von "E: Daten"  
Sicherungssatz #1 auf Medium #1
Sicherungsbeschreibung: "Band 20071115-0300"  
Mediumname: "Band 20071115-0300"  

Sicherungsart: Normal

Sicherung begonnen am 15.11.2007 um 03:01.
Sicherung abgeschlossen am 15.11.2007 um 03:44.
Verzeichnisse: 3066
Dateien: 24754
Bytes: 6.898.720.368
Zeit:  43 Minuten und  41 Sekunden
Sicherung von "System State" (mit Schattenkopie)   
Sicherungssatz #2 auf Medium #1
Sicherungsbeschreibung: "Band 20071115-0300"  
Mediumname: "Band 20071115-0300"  

Sicherungsart: Kopieren

Sicherung begonnen am 15.11.2007 um 03:44.
Sicherung abgeschlossen am 15.11.2007 um 03:47.
Verzeichnisse: 172
Dateien: 2611
Bytes: 489.327.688
Zeit:  2 Minuten und  8 Sekunden


Mit Batch habe ich dies nun folgendermaßen gelöst.

@echo off
set "Infile=test.log"  

find /n "Sicherung begonnen" %Infile% > rctmp.txt  
for /F "delims= skip=2 tokens=1" %%a in (rctmp.txt) do if not defined zeile1 set "zeile1=%%a"  

find /n "Sicherung abgeschlossen" %Infile% > rctmp.txt  
for /F "delims= skip=2 tokens=1" %%a in (rctmp.txt) do if not defined zeile2 set "zeile2=%%a"  

find /n "Sicherung begonnen" %Infile% > rctmp.txt  
for /F "delims= skip=2 tokens=1" %%a in (rctmp.txt) do set zeile3=%%a  

find /n "Sicherung abgeschlossen" %Infile% > rctmp.txt  
for /F "delims= skip=2 tokens=1" %%a in (rctmp.txt) do set zeile4=%%a  

set /a Zeile5+=%Zeile4%+6

@echo off & setlocal
set "Infile=test.log"  
set "OutFile=output.txt"  

echo Schneide aus: Zeile 0 - %Zeile1%
for /f "tokens=1* delims=:" %%i in ('findstr /n $ "%InFile%"') do if %%i leq %Zeile1% if "%%j"=="" (echo.>>"%OutFile%") else echo %%j>>"%OutFile%"  
echo Fertig.

echo.

echo Schneide aus: Zeile %Zeile2% - %Zeile3%
for /f "tokens=1* delims=:" %%i in ('findstr /n $ "%InFile%"') do if %%i geq %Zeile2% if %%i leq %Zeile3% if "%%j"=="" (echo.>>"%OutFile%") else echo %%j>>"%OutFile%"  
echo Fertig.

Echo.

echo Schneide aus: Zeile %Zeile4% - %Zeile5%
for /f "tokens=1* delims=:" %%i in ('findstr /n $ "%InFile%"') do if %%i geq %Zeile4% if %%i leq %Zeile5% if "%%j"=="" (echo.>>"%OutFile%") else echo %%j>>"%OutFile%"  
echo Fertig.

Echo.
pause

@bastla
Das VB-Script sieht schonmal sehr nett aus, und läuft auch super flott durch face-big-smile
Ich werd mich mal ranmachen, den Code zu verstehen und an meine Bedürfnisse anzupassen face-smile
lorus11
lorus11 13.12.2007 um 10:14:46 Uhr
Goto Top
Sooo das ganze umgesetzt auf das VB-Script

Quelle = "Test.log"  
Ziel = "output.txt"  

BisText = "Sicherung begonnen"  
VonText = "Sicherung abgeschlossen"  

Set fso = CreateObject("Scripting.FileSystemObject")  
LogText = Split(fso.OpenTextFile(Quelle, 1).ReadAll, vbCrLF)
LogZeilen = UBound(LogText)

BisZeile1 = 0
BisLen = Len(BisText)
For i = 0 To LogZeilen
	If Left(LogText(i), BisLen) = BisText Then
		BisZeile1 = i
		Exit For
	End If
Next

VonZeile1 = 0
VonLen = Len(VonText)
For i = BisZeile1 To LogZeilen
	If Left(LogText(i), VonLen) = VonText Then
		VonZeile1 = i
		Exit For
	End If
Next

BisZeile2 = 0
BisLen = Len(BisText)
For i = VonZeile1 To LogZeilen
	If Left(LogText(i), BisLen) = BisText Then
		BisZeile2 = i
		Exit For
	End If
Next

VonZeile2 = 0
VonLen = Len(VonText)
For i = BisZeile2 To LogZeilen
	If Left(LogText(i), VonLen) = VonText Then
		VonZeile2 = i
		Exit For
	End If
Next

BisZeile3 = VonZeile2 + 6

If (BisZeile1 * BisZeile2 * Biszeile3 * VonZeile1 * VonZeile2) Then
	Set Z = fso.OpenTextFile(Ziel, 2, True)
	For i = 0 To BisZeile1
		Z.WriteLine LogText(i)
	Next

	Z.WriteLine "----------------------------------------------------------------------------"  
	Z.WriteBlankLines 1     '1 Leerzeilen erzeugen  
	Z.WriteLine "----------------------------------------------------------------------------"  

	For i = VonZeile1 To BisZeile2
		Z.WriteLine LogText(i)		
	Next

	Z.WriteLine "----------------------------------------------------------------------------"  
	Z.WriteBlankLines 1     '1 Leerzeilen erzeugen  
	Z.WriteLine "----------------------------------------------------------------------------"  

	For i = VonZeile2 To BisZeile3
	Z.WriteLine LogText(i)		
	Next
	Z.Close
Else
	WScript.Echo "Logdaten nicht korrekt!"  
	WScript.Quit 1
End If

Jetzt müsste ich nur noch wissen, wie ich den Dateinamen (Quelle) vom Batch an das vbs übergeben kann.
Der Dateiname ist in dem Sicherungsbatch als Variable vorhanden.
bastla
bastla 13.12.2007 um 10:25:54 Uhr
Goto Top
Hallo lorus11!

Zur Parameterübergabe kannst Du so vorgehen:
If WScript.Arguments.Count < 1 Then
	WScript.Echo "Keine Quelldatei angegeben!"  
	WScript.Quit 1
End If
Quelle = WScript.Arguments(0)

Ziel = "D:\Defaultziel.txt"  
If WScript.Arguments.Count > 1 Then Ziel = WScript.Arguments(1)
...
Der Quelldateiname wird zwingend verlangt, der Zieldateiname kann (als zweiter Parameter) ebenfalls übergeben werden, ansonsten gilt der Defaultname.

Aufruf:
cscript //nologo "C:\Scripts\TrimLog.vbs" "D:\Test.log" "D:\output.txt" || goto :Fehler 
bzw
cscript //nologo "C:\Scripts\TrimLog.vbs" "%Quelldatei%" "%Zieldatei%" || goto :Fehler 

Grüße
bastla
lorus11
lorus11 14.12.2007 um 09:41:44 Uhr
Goto Top
Vielen Dank das klappt super face-smile

Ich habe nun ein sehr merkwürdiges Problem.
Und zwar kann das VBSkript die Logdateien, die direkt von NTBackup erstellt werden, nicht verarbeiten.

Kopiere ich den Inhalt "per Hand" in eine neue Datei, dann ist diese Datei halb so groß wie die Ursprüngliche und das VBSkript funktioniert mit dieser dann auch.


Woran könnte das liegen?
Biber
Biber 14.12.2007 um 09:56:33 Uhr
Goto Top
Moin lorus11,
Woran könnte das liegen?
Sonnenflecken, Seitenwind oder aber NTBackup schreibt in Unicode. face-wink

Dann müsstest Du hier:
LogText = Split(fso.OpenTextFile(Quelle, 1).ReadAll, vbCrLF)
...als VIERTEN Parameter von OpenTextFile ein "-1" für "NimmDatDingenAlsUniKot" angeben.

LogText = Split(fso.OpenTextFile(Quelle, 1, False, -1).ReadAll, vbCrLF)

bastla kann das aber besser erklären...

Grüße
Biber
lorus11
lorus11 14.12.2007 um 10:17:13 Uhr
Goto Top
Ahh danke dir.

Das NTBackup das als Unicode ausspuckt hab ich grad auch schon rausgefunden und wollt grade Fragen, wie ich die Textdatei von Unicode nach UTF-8 umwandeln kann face-big-smile.

Aber so gehts natürlich auch, auch wenn ich darauf sicher nie gekommen wäre face-big-smile

Split (Ausdruck,  [Trennzeichen, [Anzahl, [Vergleichen]]] )

Einstellungen für Vergleich

Wert 	Beschreibung
-1 	Führt einen Vergleich mit Hilfe der Option Compare-Anweisung durch.
0 	Führt einen binären Vergleich durch.
1 	Führt einen reinen Textvergleich durch.
2 	Nur Microsoft Access. Führt einen Vergleich durch, der auf Informationen in einer Datenbank basiert.
Biber
Biber 16.12.2007 um 17:22:18 Uhr
Goto Top
Moin lorus11,

es ist wie verhext - den meisten Kommentartext schreibe ich immer zur Erläuterung von Halbzeilern...
Wahrscheinlich eins der noch nicht ausformulierten Murphy's Laws.

In der Zeile
LogText = Split(fso.OpenTextFile(Quelle, 1, False, -1).ReadAll, vbCrLF)
..ist außen herum zwar eine Funktion Split() mit durchaus 4 möglichen Parametern.
Von der will ich aber gar nichts.
Der vierte Parameter, den ich vorgeschlagen habe, gehört zur Methode OpenTextFile() des FileSystemObjects. Schau Dir die Klammer-Auf und Klammer-Zu dieser Methode innerhalb der geposteten Zeile an, dort stehen 4 Parameter.
Von der Funktion Split(), bei der Du recherchiert hast, ist nur der Parameter 2 (Trennzeichen=vbCrLF) genutzt.

Grüße
Biber
lorus11
lorus11 17.12.2007 um 11:46:53 Uhr
Goto Top
Ahhh danke dir, nun ergibt das ganze auch etwas mehr sinn face-smile

FileSystemObject.OpenTextFile(Pfad[, E/A-Modus[, Erstellen[, Format]]])

Werte für Format

Wert	Beschreibung
-2	Datei wird wie in der System-Voreinstellung geöffnet
-1	Datei wird im Unicode-Modus geöffnet
0	Datei wird im ASCII-Modus geöffnet.
Biber
Biber 17.12.2007 um 16:05:35 Uhr
Goto Top
Moin lorus11,

und? Kann dann langsam ein Haken dran?
Oder sind noch Fragen offen?

Grüße
Biber
[Edit] Haken ist dran (THX @lorus11), also schliesse ich den Thread.[/Edit]