Batch - mit Variablen rechnen oder inkrementieren?
Hallo!
Aus einer Textdatei nach folgendem Muster
möchte ich die Summe der Zahlenwerte ermitteln. Mein Versuch sieht so aus
Links die erhoffte Ausgabe, recht die tatsächliche.
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.
Aus einer Textdatei nach folgendem Muster
Wert: 10
blabla bleh strunz
Wert: 13
blubber blub göbel dum
Wert: 26
@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
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.
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 19116
Url: https://administrator.de/forum/batch-mit-variablen-rechnen-oder-inkrementieren-19116.html
Ausgedruckt am: 22.04.2025 um 08:04 Uhr
7 Kommentare
Neuester Kommentar
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
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.
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.
Moin Jansen,
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:
[/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.
Der Output dieses Schnipsels:Wenn das Deiner Meinung nach verständlich genug ist, hänge ich das nachher um als Tutorial.
Grüße
Biber
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.
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
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
Grüße
Biber
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
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
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]
...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
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
...
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