jansen
Goto Top

Batch - mit Variablen rechnen oder inkrementieren?

Hallo!

Aus einer Textdatei nach folgendem Muster
Wert: 10
blabla bleh strunz
Wert: 13
blubber blub göbel dum
Wert: 26
möchte ich die Summe der Zahlenwerte ermitteln. Mein Versuch sieht so aus

@echo off
@set /a sum=0
@for /F "tokens=1,2" %%a in (c:\tmp.log) do (  
....@if "%%a"=="Wert:" (  
........@if NOT "%%b"=="0" (  
............@echo ZwWert=%%b
............@set /a sum=%sum%+%%b
............@echo ZwSum=%sum%
........)
....)
)
@echo EndSum=%sum%

Links die erhoffte Ausgabe, recht die tatsächliche.
ZwWert=10............ZwWert=10
ZwSum=10.............ZwSum=0
ZwWert=13............ZwWert=13
ZwSum=23.............ZwSum=0
ZwWert=26............ZwWert=26
ZwSum=49.............ZwSum=0
EndSum=49............EndSum=26
Wer kann mir sagen, wo es hier hakt und hat vor allem eine, gern auch alternative, Lösung?
Danke für alle Tips!

PS.
Zielsystem ist Win2K/XP, die betreffende Datei ist das Log von ntbackup, das auf "Ausgelassen:" und "Unterschiedlich:" geprüft werden soll. Perl, VBS etc. kommen aus "administrativen Gründen" leider nicht in Betracht.

PPS.
Den Thread Rechnen mit Variablen unter Batch habe ich gesehen und bin auch dem Link von Biber dort gefolgt, weitergebracht hat mich das leider nicht.

Content-Key: 19116

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

Printed on: April 23, 2024 at 14:04 o'clock

Member: nullplan001
nullplan001 Nov 06, 2005, updated at Mar 02, 2016 at 13:18:08 (UTC)
Goto Top
Zunächst einmal kannst du die ganzen @ außer dem vor "echo off" löschen. Schon wird die Angelegenheit übersichtlicher. Und dann war da noch die Befehlserweiterung für WINNT. Lies dir mal bei Gelegenheit CMD /? durch.
Ich habe den Fehler aber schon ausgemacht: in der Schleife musst du den Befehl
<tt>@set /a sum=%sum%+%%b</tt> in <tt>set /a sum=!sum!+%%b</tt>umwandeln

Und zwar deshalb: %sum% hat einen Wert. Dieser wird erst nach der Schleife aktualisiert. !sum! hat den Wert von %sum%, wird aber gleich in der Schleife aktualisiert. Wieso das so ist, fragst du besser Microsoft.
Member: Jansen
Jansen Nov 06, 2005 at 11:35:11 (UTC)
Goto Top
Hallo, danke für die Hilfe.

Lies dir mal bei Gelegenheit CMD /? durch.
Jo, hab ich schon, verstehe allerdings nicht genau, worauf du hinauswillst.

<tt>@set /a sum=%sum%+%%b</tt>
in <tt>set /a sum=!sum!+%%b</tt>
umwandeln.

Das produziert leider eine "Fehlender Operator"-Ausgabe.

Gruss,
Jansen
Member: Biber
Biber Nov 06, 2005, updated at Mar 02, 2016 at 13:18:43 (UTC)
Goto Top
Moin Jansen,

Wieso das so ist, fragst du besser Microsoft.
...Biber fragen geht schneller..

Der Denkfehler ist folgender: Auch wenn Du die Anweisungen in Deiner FOR..IN..DO-Schleife noch so schön formatierst und in mehrere Zeilen auseinanderziehst - der CMD-Interpreter sieht und zieht sie als eine Zeile an.
Der liest sie zur Ausführungszeit en bloc ein und löst alle darin enthaltenen Variablen einmalig auf. Alle außer den FOR-Zählvariablen, die werden in jedem Schleifendurchlauf neu befüllt.
Du kannst dieses Verhalten beeinflussen/ändern über den Befehl
"setlocal EnableDelayedExpansion" .. verzögerte Variablen-Auflösung. Steht irgendwo in der Hilfe (SET/? oder CALL /?).

[Edit]
Wenn EnableDelayedExpansion nicht gesetzt ist, bekommst Du bei Verwendung der !var!-Syntax ein Problem:
Das produziert leider eine "Fehlender Operator"-Ausgabe.
[/Edit]

Oder aber.. ohne generelle DelayedExpansion geht es über das callen einer (Pseudo-)Subroutine.
Weil ich nicht so gut im Erklären bin, zeig ich das mal in einem Batchbeispiel.
::-------snipp Summarize.bat
@echo off & setlocal
goto skipProsa
Die nächste Findstr-Zeile ist natürlich nur bei mir beim Testen sinnvoll.
Unten nach dem "goto :eof" stehen Deine Beispielzeilen (wie in der tmp.log).  
Ich schreibe alle Zeilen, die mit "Wert:" beginnen, irgendwohin.  
Bei Dir könnte dort stehen findstr /b "Wert:" c:\tmp.log>%NurWerte%  
:SkipProsa
Set "NurWerte=%temp%\NurZeilenMitWertBeginnend.txt"  
findstr /b "Wert:" Summarize.bat>%NurWerte%  
Echo Die Werte:
Type %NurWerte%
Echo -----
Call :Variante1
Call :Variante2
Call :Variante3
goto :eof
-----Ende des Haupt-Batches

:Variante1
Echo Variante1) sum wird in EINER FOR..IN..DO..Zeile addiert
set /a sum=0 
for /F "tokens=1,2" %%a in (%NurWerte%) do (       
   if "%%a"=="Wert:" (   
     if NOT "%%b"=="0" (   
        set /a sum=%sum%+%%b 
        echo ZwSum=%sum% ZwWert=%%b 
        ) ) ) 
echo EndSum=%sum%
Goto :eof
----Ende :Variante1
----
:Variante2
Echo.
Echo Variante2) sum wird in einem call:-Block addiert
set /a sum=0 
for /F "tokens=1,2" %%a in (%NurWerte%) do call :Sum2 %%a %%b  
echo EndSum=%sum%
goto :eof
----Ende :Variante2... ruft den Block ":sum2"  
----
:sum2
   if "%1"=="Wert:" (   
     if NOT "%2"=="0" (   
        set /a sum=%sum%+%2 
        echo ZwSum=%sum% ZwWert=%2  
        ) ) ) 
Goto :eof
----Ende :Sum2-"Subroutine"  
-------
:Variante3
Echo.
Echo Variante3) ...etwas schlankere Version von Variante2
set /a sum=0 
for /F "tokens=2" %%a in (%NurWerte%) do call :Sum3 %%a  
echo EndSum=%sum%
goto :eof
----Ende :Variante3... ruft den Block ":sum3"  
----
:sum3
set /a sum+=%1 
echo ZwSum=%sum% ZwWert=%1  
Goto :eof
----Ende :Sum3-"Subroutine"  

Wert: 10 
blabla bleh strunz 
Wert: 0 
Sülz di bülz 
Wert: 13 
blubber blub göbel dum 
Wert: 26
-------snapp Summarize.bat
Der Output dieses Schnipsels:
Summarize.bat
Die Werte:
Wert: 10
Wert: 0
Wert: 13
Wert: 26
-----
Variante1) sum wird in EINER FOR..IN..DO..Zeile addiert
ZwSum=0 ZwWert=10
ZwSum=0 ZwWert=13
ZwSum=0 ZwWert=26
EndSum=26

Variante2) sum wird in einem call:-Block addiert
ZwSum=0 ZwWert=10
ZwSum=10 ZwWert=13
ZwSum=23 ZwWert=26
EndSum=49

Variante3) ...etwas schlankere Version von Variante2
ZwSum=10 ZwWert=10
ZwSum=10 ZwWert=0
ZwSum=23 ZwWert=13
ZwSum=49 ZwWert=26
EndSum=49
Wenn das Deiner Meinung nach verständlich genug ist, hänge ich das nachher um als Tutorial.

Grüße
Biber
Member: Jansen
Jansen Nov 06, 2005 at 14:26:57 (UTC)
Goto Top
Danke!

Das Setzen von EnableDelayedExpansion funktioniert, und diese Variante werde ich auch verwenden (oder spricht etwas dagegen?).

Aber danke auch für die Alternativen, da habe ich wieder mehr gelernt als ursprünglich erhofft. face-smile
Member: Biber
Biber Nov 06, 2005, updated at Mar 02, 2016 at 13:15:31 (UTC)
Goto Top
Moin Jansen,
ich habe auch in meiner CMD-"Workbench" immer das "EnableDelayedExpansion" gesetzt. Geht ja auch per Registry oder per AutoRun-Batch.
Kann aber seine Tücken haben, da ja nun alles zwischen zwei Ausrufungszeichen als Variable gnadenlos aufgelöst wird.
Dafür habe ich in meinem Workshop Batch for Runaways - Part II - Ein bisschen Handwerkszeug ein Beispiel, wo das in die Grütze geht. Wenn man/frau diesen Fall im Hinterkopf hat, ist es kein Problem.

Grüße
Frank / der Biber aus Bremen
Member: Jansen
Jansen Nov 06, 2005 at 21:12:21 (UTC)
Goto Top
Hmm ja, da werde ich die Auswertung wohl lieber per externem Batch erledigen, anstatt EDE direkt in das meterlange Backup-Script einzubauen. face-smile
Nochmals Danke für dein geduldiges Erklären!

Gruss,
Jansen
Member: Biber
Biber Nov 06, 2005, updated at Mar 02, 2016 at 13:16:00 (UTC)
Goto Top
Na ja, Jansen,
ausreden wollte ich es Dir ja auch nicht.. nur die Tücken des Objekts aufzeigen.

In Deinem Fall kannst Du natürlich auch irgendwo in Deinem meterlangen Backup-Skript
(soll ich Dir das mal ein bisschen zusammendampfen? *gg)
noch einen kleinen 3-Zeilen Call-Block namens "getSumme" einbauen... ["set /a sum=0" muss vorher erfolgen]
..
:getSumme
setlocal EnableDelayedExpansion & set "NurWerte=c:\tmp.log"  
for /F "tokens=2" %%a in (%NurWerte%) do set /a sum=!sum!+%%a  
EndLocal & goto :eof
...
...hat ja schon einen gewissen Charme und würde ich wohl auch so machen.
Dann hast Du das "EnableDelayedExpansion" nur in diesem kleinen Block (durch "EndLocal" wieder auf vorherigen Stand gesetzt).

Andererseits .. ohne das DelayedExpansion-Feature hättest Du in Deinem Code eine Batch-Zeile mehr..was soll der Geiz?
Selbst meine Oneliner belegen auf manchen Festplatten 16.384 Bytes, obwohl keine Hundert Zeichen drin stehen.
Kannst also ruhig ein, zwei Zeilen mehr reinschreiben - kostet das Gleiche.

Stressarmen Wochenanfang
Biber