.sessl
Goto Top

Auslesen der drittletzten Zeile ..

Hallo zusammen,

ich habe nach einer ganzen Weile, mit Eurer Hilfe bei ähnlichen Problemen, mir ein funktionierendes Script gebastelt.
Mein Problem ist, dass je größer die Logdatei wird, der Durchlauf Ewigkeiten dauert.

Meine Frage, was könnte ich noch verbessern bzw. mir an Code sparen um das Script evtl. performanter zu machen?


Was macht das Script:
Eine Installationsroutine schreibt in ein vorgegebenes Logfile den akt. Status der Installation, sollte es einen Fehler geben oder fertig sein, wird am Ende der Logdatei eine Anweisung geschrieben.
Genau diese Anweisung möchte ich aus dem Log auslesen und mich darüber per Mail informieren lassen.

Das Problem, nachdem die Anweisung ins Log geschrieben wurde, werden noch zwei Leerzeilen angefügt, so dass ich nicht sagen kann, ließ mir die letzte Zeile aus.
Aus diesem Grund lasse ich das Script zwei mal durchlaufen. Im ersten Durchlauf wird die Anzahl der Zeilen ausgekundschaftet und 2 abgezogen. Im zweiten Lauf nun die "letzte" ausgelesen.

Ein weiteres Problem ist, wenn im ersten Lauf 388.082 Zeilen gezählt werden, die Datei aber in diesem Augenblick befüllt wird, evtl. sogar mit der ersehnten Anweisung, wird diese jedoch noch nicht im zweiten Lauf wahrgenommen, da ja die Zeile 388.080 ausgelesen wird. D.h. erst in einem weiteren kompletten Lauf wird die Anweisung erkannt, ausgewertet und mir eine E-Mail geschickt.

Ich hoffe Ihr könnt mir folgen, falls nicht, einfach fragen.


@echo off

set "instlog=c:\inst.log"  
set "anweisung=Waiting for an answer from GUI"  

:start

:: Nummer der letzten Zeile ausfindig machen und zwei Zeilen abziehen (Leerzeilen im Log)
FOR /F "delims=:" %%A IN ('findstr /N .* "%instlog%"') DO set "zeile=%%A"  
set /A "zeile=%zeile%-2"  

:: Inhalt der Vorvorletzen Zeile in eine Variable einlesen
Set /a "cnt=1"  
Set /a "n=%zeile%"  
for /F "delims=" %%i in ('findstr /N .* "%instlog%"') do call :setvarFixLine %n% "%%i"   

goto step1

:: Sprungmarke #setvarFixLine
:setvarFixLine
If %cnt%==%1 Set "Var=%~2"  
Set /a "cnt+=1"   
goto :eof
:: Sprungmarke #setvarFixLine


:step1

:: Inhalt der Variable (VAR) zurecht stutzen
set "var=%var:~-30,30%"  

:: Inhalt der Variable mit dem gewünschten Zeileninhalt vergleichen
if "%var%" EQU "%anweisung%" goto gui_wait  

goto start


:gui_wait
Ausgabe per Email ..

ps. könnte mir noch jmd erklären, was es mit ("Var=%~2") bei setvarFixLine auf sich hat?

Vielen Dank.

Gruß
Tobias

Content-Key: 231100

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

Printed on: April 19, 2024 at 03:04 o'clock

Member: Sheogorath
Sheogorath Feb 26, 2014 updated at 20:34:45 (UTC)
Goto Top
Moin,

wie wäre es damit:
@echo off

set "instlog=c:\inst.log"  
set "anweisung=Waiting for an answer from GUI"  

:start
findstr /c:"%anweisung%" "%instlog%">nul  
if %errorlevel% eq 0 (
 goto :gui_wait
)
goto :start


:gui_wait
Ausgabe per Mail

Gruß
Chris
Member: bastla
bastla Feb 26, 2014 updated at 20:44:06 (UTC)
Goto Top
... oder etwas kürzer (ab Zeile 7)
findstr /ic:"%anweisung%" "%instlog%">nul || goto :start  
echo Ausgabe Mail
Ansonsten noch ein Hinweis: Wenn die letzten beiden Zeilen leer sind, würde ein
for /f "usebackq delims=" %%i in ("%instlog%") do set "Zeile=%%i"
in der Varaiablen %Zeile% den Inhalt der letzten nicht leeren Zeile liefern, wobei aber natürlich trotzdem einmal alle Zeilen durchlaufen werden müssten.

Grüße
bastla
Member: .Sessl
.Sessl Feb 26, 2014 at 21:03:54 (UTC)
Goto Top
Hi,

vielen Dank für die schnellen Antworten.

Was ich vergessen hatte zu erwähnen ist, dass das Logfile fortlaufend ist. Soll heißen, falls es während der Installation bereits mehrfach zu Zwischenfällen kam, wird die Anweisung auch mehrfach im Logfile stehen. Deshalb kann ich nicht einfach von oben nach unten oder umgekehrt suchen, da beim simplen durchgehen ältere Einträge gefunden werden, was wiederum ein Fehlverhalten nach sich zieht.

Mein Fehler .. Sorry!!!
Member: pieh-ejdsch
Solution pieh-ejdsch Feb 26, 2014, updated at Feb 27, 2014 at 14:08:15 (UTC)
Goto Top
moin,

var wird mit den zweiten Parameter, der in der forschleife übergeben wird, befüllt. Ist aber nicht sehr performant, da jede Zeilennummer für sich überprüft wird.
Alternativ:
for /f %%i in (' "find /c /v "" <logfile.log" ') do set /a n = %%i -2  
more +%n% logfile.log |find "%Anweisung%" && echo mach was....  

@chris, er will doch die letzte gültige Zeile im LOG auslesen. Das wird wohl schon paarmal drinstehen.

@echo off

set "instlog=c:\inst.log"  
set "anweisung=Waiting for an answer from GUI"  

set "Anweisung=%Anweisung: =^ %"  

:start
for /f "usebackq tokens=1-6" %%a in ("%instlog%") do if %%a^ %%b^ %%c^ %%d^ %%e^ %%f equ %Anweisung% (set OK=1) else set "OK="  
if defined OK goto :gui_wait
goto :start

:gui_wait
 rem Ausgabe per Mail ..

[OT]
man diese Surface TastaturMatte ist echt gewöhnungsbedürftig ....
[/OT]

Gruß Phil
Member: bastla
bastla Feb 26, 2014, updated at Mar 03, 2014 at 14:12:58 (UTC)
Goto Top
@ PH
Das wird wohl schon paarmal drinstehen.
Ist ja egal, wie oft - wenn das letzte Vorkommen gefragt ist, genügt eine Schleife über das "findstr"-Ergbenis:
set "Meldung="  
for /f "delims=" %%i in ('findstr /ic:"%anweisung%" "%instlog%"') do set "Meldung=%%i"  
if not defined Meldung goto :start
echo Mail mit %Meldung%
Grüße
bastla
Member: Endoro
Solution Endoro Feb 27, 2014 updated at 14:08:22 (UTC)
Goto Top
Hey,
Batch ist 1. langsam und 2. für grosse Textdateien nicht geeignet, weil da vieles wie zB die For Schleife nicht funktioniert. Nimm dann entweder eine andere Scriptsprache oder GNUWin32 for Windows.

Hier ein Beispiel für die "drittletzte" Zeile, wobei der Text nur einmal durchlaufen wird:
@ECHO OFF &SETLOCAL disableDelayedExpansion
FOR %%a IN (*.txt) DO CALL:GetLine "%%~a"  
GOTO:EOF

:GetLine
SETLOCAL enableDelayedExpansion
FOR /f "usebackqdelims=" %%b IN ("%~1") DO (  
	SET "LastButTwo=!SecondLast!"  
	SET "SecondLast=!Last!"  
	SET "Last=%%b"  
)
ECHO(Drittletzte Zeile IN "%~1" ist:  
ECHO(!LastButTwo!
EXIT /b
Hier wieder batchtypische Einschränkungen:
1) alle Ausrufezeichen werden gelöscht
2) funktioniert nicht mit utf-8/utf-16 bzw. Unicode
3) Leerzeilen werden nicht mitgezählt
Gruss.
Member: .Sessl
.Sessl Feb 27, 2014 at 13:27:27 (UTC)
Goto Top
Hallo Chris,

funktioniert leider nicht.
Die Schleife läuft unentwegt durch und findet die Anweisung generell nicht.

Trotzdem Danke!
Member: .Sessl
.Sessl Feb 27, 2014, updated at Mar 03, 2014 at 14:15:46 (UTC)
Goto Top
Hallo Phil,

vielen Dank für deine Hilfe!
Das Script funktioniert bestens, läuft mit 12 sek. bei 420.000 Zeilen sogar sehr schnell, kommt aber Performancetechnisch nicht an bastla's Script (2 sek.) ran.

Dennoch vielen Dank für den weiteren Denkanstoß, wird mir sicher noch bei weiteren Projekten hilfreich sein!

Danke!


Gruß
Tobias


[edit]

Mein Fehler!
Dein Script ist das einzig zu 100% funktionierende. Ich danke dir!

[/edit]
Member: .Sessl
.Sessl Feb 27, 2014 at 13:45:46 (UTC)
Goto Top
Hallo bastla,

oh man, dümmer hätte ich mich glaube nicht anstellen können :/
Danke fürs vereinfachen und mit der Laufzeit von 2 Sek. bei 420.000 Zeilen rasant, performanter geht's nicht.

Vielen Dank für die Hilfe!


Gruß
Tobias
Member: .Sessl
.Sessl Feb 27, 2014 at 14:07:24 (UTC)
Goto Top
Hallo Endoro,

naja für die 3. Einschränkung habe ich ja den 1. Lauf gehabt, welche die Leerzeilen mit gezählt hatte.
Aber auch dir ein Dankeschön für den Lösungsansatz, funktioniert ebenfalls sehr gut.

Danke.

Gruß
Tobias
Member: .Sessl
.Sessl Mar 03, 2014 at 14:14:35 (UTC)
Goto Top
Das Problem, so bald ein weiterer Eintrag irgendwo schon mal im Log vorkam, wird dieser gezogen. Hilf leider nicht ganz.