Problem mit CountTokens - bzw. Variablenübergabe
Hallo liebe Leute,
mein Name ist Leopold - ich bin erst seit heute Mitglied - habe hier aber schon als Gast eine Menge gelernt - ich möchte mich dafür bedanken. Ich bin zwar gelernter Programmierer, bin aber mehr im Datenbankbereich unterwegs - falls es da Fragen gibt, kann ich vielleicht Unterstützung geben. Ich habe zwar auch schon Batchprogrammierung gemacht, bin aber auf dem Gebiet kein Experte. Also bitte nicht schimpfen wenn mir etwas nicht auf Anhieb klar ist
Ich schreibe an einem Batch, der eine Ini Datei ausliest. Die Ini Datei ist in Sektionen aufgeteilt und wird auch sektionsweise ausgelesen. Die einzelnen Sätze in den Sektionen sind immer gleich aufgebaut - aber haben unterschiedliche Anzahlen von Argumenten, die durch Trennzeichen voneinander abgegrenzt werden. In Sektion1 könnten es 5 Argumente pro Satz sein, die durch ein Pipe Zeichen voneinander getrennt sind, in Sektion2 sind es vielleicht nur 2 Argumente, eventuell sind auch die Trennzeichen verschieden. Ich habe also eine unterschiedliche Anzahl von Tokens und evtl.unterschiedliche Delimiter, aber das könnte ich noch vereinheitlichen. Die unterschiedliche Anzahlan Tokens wird aber bleiben. Oder ich müsste mit Dummys auffüllen, was ich aber nicht möchte.
Es gibt hier in der Community ein wunderbares Script das die Anzahl der Tokens zählt - und das macht bei mir ein für mich nicht einleutendes Problem.
Hier mein Quellcode
Was hier passiert ist relativ simpel. In der For Schleife wird die Sektion in der Ini Datei gesucht und ab da wird satzweise gelesen, bis die nächste Sektion erreicht ist. Jeder gelesene Satz wird zum Token zählen geschickt. Wenn die Sektion zu Ende ist, geht es zur Sprungadresse :weiter weiter. Da wird noch mal ein Teststring zum Token zählen geschickt. Aus gutem Grund. Die Variable nTokens steht nämlich in der Schleife nicht zur Verfügung, wird nicht befüllt oder nicht aktualisiert. Beim Testaufruf aber schon. Und ich komme nicht dahinter, warum es so ist. In der Schleife steht in !key! ein ganzer Satz aus der IniDatei, das kann man vielleicht eleganter machen aber darum geht es mir jetzt nicht. Die Funktion CountTokens wird ordnungsgemäß aufgerufen und am Ende der Funktion CountTokens wird nTokens auch ordnungsgemäß befüllt und ausgegeben. Auch bei dem Aufruf aus der Schleife. Trotzdem steht die Variable im aufrufenden Programm nicht zur Verfügung. Bei meinem Teststring passiert im Prinzip das Gleiche. Es wird ein String übergeben und der Delimiter und da steht im aufrufenden Programm die Variable nTokens dann anschließend zur Verfügung. Zwei im Prinzip gleiche Aufrufe mit unterschiedlichen Folgen. Ich weiß nicht woran es liegt - ist am Aufruf innerhalb der Schleife was falsch? - kann eigentlich nicht sein, weil unten in der Funktion alles richtig läuft. Gibt die Funktion den Rückgabewert nicht richtig zurück? - kann eigentlich auch nicht sein, weil es beim Teststring ja funktioniert. Es liegt auch nicht am setlocal - auch wenn ich den Aufruf in der Schleife nach endlocal mache habe ich das gleiche Problem. Es liegt auch nicht an den Sätzen aus der Ini Datei. Wenn ich meinen Teststring in die Inidatei schreibe, habe ich das gleiche Problem. Wie kann ich die Funktion überreden den Wert richtig zurückzugeben bzw. die Schleife dazu bewegen, die Funktion richtig aufzurufen oder den zurückgegebenen Wert auch anzunehmen? Im "richtigen" Programm soll natürlich innerhalb der Schleife abhängig von der Anzahl der Tokens etwas passieren - ich kann weder auf die Schleife noch auf das Zählen der Tokens verzichten. Ich bitte um Hinweise. Vielen Dank für Eure Mühe.
LG aus HH
Leopold
mein Name ist Leopold - ich bin erst seit heute Mitglied - habe hier aber schon als Gast eine Menge gelernt - ich möchte mich dafür bedanken. Ich bin zwar gelernter Programmierer, bin aber mehr im Datenbankbereich unterwegs - falls es da Fragen gibt, kann ich vielleicht Unterstützung geben. Ich habe zwar auch schon Batchprogrammierung gemacht, bin aber auf dem Gebiet kein Experte. Also bitte nicht schimpfen wenn mir etwas nicht auf Anhieb klar ist
Ich schreibe an einem Batch, der eine Ini Datei ausliest. Die Ini Datei ist in Sektionen aufgeteilt und wird auch sektionsweise ausgelesen. Die einzelnen Sätze in den Sektionen sind immer gleich aufgebaut - aber haben unterschiedliche Anzahlen von Argumenten, die durch Trennzeichen voneinander abgegrenzt werden. In Sektion1 könnten es 5 Argumente pro Satz sein, die durch ein Pipe Zeichen voneinander getrennt sind, in Sektion2 sind es vielleicht nur 2 Argumente, eventuell sind auch die Trennzeichen verschieden. Ich habe also eine unterschiedliche Anzahl von Tokens und evtl.unterschiedliche Delimiter, aber das könnte ich noch vereinheitlichen. Die unterschiedliche Anzahlan Tokens wird aber bleiben. Oder ich müsste mit Dummys auffüllen, was ich aber nicht möchte.
Es gibt hier in der Community ein wunderbares Script das die Anzahl der Tokens zählt - und das macht bei mir ein für mich nicht einleutendes Problem.
Hier mein Quellcode
Rem Aufrufendes Programm
@echo off&setlocal
set "inifile=MYBATCH.INI"
set "section=TESTSECTION"
for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do (
for /f "tokens=1* delims=$" %%b in ('more +%%a^<"%inifile%"') do (
set "key=%%b"
setlocal enabledelayedexpansion
if "!key:~,1!"=="[" (endlocal&goto :weiter)
call :CountTokens "!key!" "|"
echo In Section %section% hat der DS %nTokens% Tokens
endlocal
)
)
:weiter
set teststring="Hallo|Hallo|hallo|Hallo|Hallo|hallo"
call :CountTokens %teststring% "|"
echo Teststring hat %nTokens% Tokens
goto:eof
Rem Subroutine Tokenszählen
:CountTokens
setlocal
set "str=%~1"
set nTokens=1
:CountTokensLoop
call set "newstr=%%str:%~2=%%"
if "%newstr%" neq "%str%" (
set /a nTokens+=1
call set "str=%%str:*%~2=%%"
goto :CountTokensLoop
)
endlocal & set nTokens=%nTokens%
echo Der Satz hat %nTokens% Tokens
goto:eof
Was hier passiert ist relativ simpel. In der For Schleife wird die Sektion in der Ini Datei gesucht und ab da wird satzweise gelesen, bis die nächste Sektion erreicht ist. Jeder gelesene Satz wird zum Token zählen geschickt. Wenn die Sektion zu Ende ist, geht es zur Sprungadresse :weiter weiter. Da wird noch mal ein Teststring zum Token zählen geschickt. Aus gutem Grund. Die Variable nTokens steht nämlich in der Schleife nicht zur Verfügung, wird nicht befüllt oder nicht aktualisiert. Beim Testaufruf aber schon. Und ich komme nicht dahinter, warum es so ist. In der Schleife steht in !key! ein ganzer Satz aus der IniDatei, das kann man vielleicht eleganter machen aber darum geht es mir jetzt nicht. Die Funktion CountTokens wird ordnungsgemäß aufgerufen und am Ende der Funktion CountTokens wird nTokens auch ordnungsgemäß befüllt und ausgegeben. Auch bei dem Aufruf aus der Schleife. Trotzdem steht die Variable im aufrufenden Programm nicht zur Verfügung. Bei meinem Teststring passiert im Prinzip das Gleiche. Es wird ein String übergeben und der Delimiter und da steht im aufrufenden Programm die Variable nTokens dann anschließend zur Verfügung. Zwei im Prinzip gleiche Aufrufe mit unterschiedlichen Folgen. Ich weiß nicht woran es liegt - ist am Aufruf innerhalb der Schleife was falsch? - kann eigentlich nicht sein, weil unten in der Funktion alles richtig läuft. Gibt die Funktion den Rückgabewert nicht richtig zurück? - kann eigentlich auch nicht sein, weil es beim Teststring ja funktioniert. Es liegt auch nicht am setlocal - auch wenn ich den Aufruf in der Schleife nach endlocal mache habe ich das gleiche Problem. Es liegt auch nicht an den Sätzen aus der Ini Datei. Wenn ich meinen Teststring in die Inidatei schreibe, habe ich das gleiche Problem. Wie kann ich die Funktion überreden den Wert richtig zurückzugeben bzw. die Schleife dazu bewegen, die Funktion richtig aufzurufen oder den zurückgegebenen Wert auch anzunehmen? Im "richtigen" Programm soll natürlich innerhalb der Schleife abhängig von der Anzahl der Tokens etwas passieren - ich kann weder auf die Schleife noch auf das Zählen der Tokens verzichten. Ich bitte um Hinweise. Vielen Dank für Eure Mühe.
LG aus HH
Leopold
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 179617
Url: https://administrator.de/contentid/179617
Ausgedruckt am: 22.11.2024 um 18:11 Uhr
14 Kommentare
Neuester Kommentar
Hallo bastla,
ich bin mir sehr sicher, dass Du damit recht hast. Allerdings stehe ich gerade auf dem Schlauch und verstehe nicht warum. "nTokens" wird doch in einer neuen cmd-Instanz gesetzt. Warum steht die Variable dann in der for-Schleife bei Verwendung mit % nicht zur Verfügung?
Gruß icsat
ich bin mir sehr sicher, dass Du damit recht hast. Allerdings stehe ich gerade auf dem Schlauch und verstehe nicht warum. "nTokens" wird doch in einer neuen cmd-Instanz gesetzt. Warum steht die Variable dann in der for-Schleife bei Verwendung mit % nicht zur Verfügung?
Gruß icsat
Moin Leopold.Bloom,
willkommen im Forum.
Natürlich!
Grüße
Biber
willkommen im Forum.
Natürlich!
Grüße
Biber
Hallo Leopold,
ich denke Du darfst Deine Threads schon selber als gelöst kennzeichen. Wer außer Dir sollte sonst beurteilen können ob Dein Problem für dich ausreichend gelöst wurde?
Gelöst war das Problem ja schon mit bastla's Post aber es hätte ja durchaus sein können, dass Du noch Fragen nach dem "Warum?" (so wie ich oben) hast.
Und außerdem: Warum solltest Du die Gelöst funktion nicht nutzen, wo sie Dir doch zur Verfügung steht?
Gruß icsAT
ich denke Du darfst Deine Threads schon selber als gelöst kennzeichen. Wer außer Dir sollte sonst beurteilen können ob Dein Problem für dich ausreichend gelöst wurde?
Gelöst war das Problem ja schon mit bastla's Post aber es hätte ja durchaus sein können, dass Du noch Fragen nach dem "Warum?" (so wie ich oben) hast.
Und außerdem: Warum solltest Du die Gelöst funktion nicht nutzen, wo sie Dir doch zur Verfügung steht?
Gruß icsAT
Hallo Leopold!
Performancemäßig sollte allerdings Dein ursprünglicher Ansatz Vorteile haben (habe ich nicht getestet und spielt vielleicht bei einer Ini-Datei auch keine so große Rolle) ...
Noch ein Hinweis zum Vergleich mit "
Grüße
bastla
Einen sauberen Ausstieg aus einer doppelten For Schleife
... brauchst Du nicht, wenn Du die erste Schleife eliminierst - die Zeilennummer kannst Du ja vorweg bestimmen und in einer Variablen platzieren - im Gegenzug könntest Du dann die Variable !key!
einsparen, wenn grundsätzlich "delayedExpansion
" vermieden werden soll und die Prüfung auf "[ ist enthalten" schon genügen würde (genauer wäre natürlich findstr /b
, was aber am für Batch kontraproduktiven Delimiter "|" scheitert); schließlich kann noch per Schaltervariablen (ich hatte mich schon für %InSection%
entschieden bevor ich Deine "%done%-Variante
" gesehen habe) die Schleife "ordnungsgemäß" beendet werden:for /f "delims=:" %%a in ('findstr /binc:"[%section%]" "%inifile%"') do set /a Zeile=%%a
set "InSection=True"
setlocal enabledelayedexpansion
for /f "tokens=1* delims=$" %%b in ('more +%Zeile%^<"%inifile%"') do (
echo "%%b"|findstr "[">nul && set "InSection="
if defined InSection (
call :CountTokens "%%b" "|"
if !max_tokens! LSS !nTokens! set /a max_tokens=!nTokens!
)
echo In Section %section% hat der DS !max_tokens! Tokens
)
endlocal
Noch ein Hinweis zum Vergleich mit "
LSS
": Wenn Du Anführungszeichen verwendest, wird ein String-Vergleich durchgeführt (und dann ist "15" kleiner als "3") ...Grüße
bastla
Hallo icsAT!
Grüße
bastla
Warum steht die Variable dann in der for-Schleife bei Verwendung mit % nicht zur Verfügung?
Bei "nicht-verzögerter Variablenauflösung" (also im Normalfall) wird zu Beginn der Schleife der jeweilige Wert der Varaiblen ermittelt - Änderungen daran können zwar in der Schleife (oder einem davon aufgerufenen Unterprogramm) erfolgen, allerdings "interessiert" sich der Interpreter erst nach Ende der Schleife dafür - mit dem Auftrag zur "verzögerten" Auflösung der Variablen (durch die Schreibweise !nTokens!
) wird diese bei jedem Schleifendurchlauf neuerlich vorgenommen ...Grüße
bastla
Hallo bastla,
danke für die Erklärung, wobei mir das Thema grundsätzlich klar ist. Ich war vorhin nur der Meinung mit der Verwendung von call und einer neuen cmd-Instanz könnte man das umgehen aber da war ich wohl auf dem Holzweg. Ich glaube ich habe da was mit der Verwendung von dynamischen Variablennamen verwechselt.
Gruß icsAT
danke für die Erklärung, wobei mir das Thema grundsätzlich klar ist. Ich war vorhin nur der Meinung mit der Verwendung von call und einer neuen cmd-Instanz könnte man das umgehen aber da war ich wohl auf dem Holzweg. Ich glaube ich habe da was mit der Verwendung von dynamischen Variablennamen verwechselt.
Gruß icsAT
Aloha Leopold,
ui, so viel Text mussten wir schon lange nicht mehr im Batch-Bereich lesen, schon gar nicht so viele Fragen, die sonst keiner stellt *gg*
Also als Erstes mal:
Der Unterschied zwischen
würde dir ein
Im Gegenzug jedoch gibt dir
kein OK aus, weil
Wenn
Du hast zwar
kann nicht funktionieren, wie du es willst, denn die Ausgabe wäre jetzt
Derartige Spielchen gingen nur, wenn
Das mit dem Lesezugriff ist eine gute Frage, ich nehme an, dieser beginnt beim ersten
macht die Datei 3x auf und 3x zu, während
1x auf- und zumacht
Was passiert, wenn die Batch abschmiert, ganz einfach: Dann gibt es keinen Zugriff auf die Datei und sie ist somit nicht in Benutzung, also geschlossen.
greetz André
edit: Es ging irgendwo noch um eine Pipe? Ich sag's ja: Zu viel Text vor'm Frühstück
ui, so viel Text mussten wir schon lange nicht mehr im Batch-Bereich lesen, schon gar nicht so viele Fragen, die sonst keiner stellt *gg*
Also als Erstes mal:
Der Unterschied zwischen
&
und &&
ist der, dass ein Befehl nach einer &
Verknüpfung immer ausgeführt wird, während mit einem &&
der nachfolgende Befehl nur ausgeführt wird, wenn der erste Befehl erfolgreich war, sprich:echo "abc"|findstr "[">nul & echo OK
OK
ausgeben, egal, ob findstr
nun erfolgreich etwas gefunden hat oder nicht, im Prinzip ist es wieecho "abc"|findstr "[">nul
echo OK
echo "abc"|findstr "[">nul && echo OK
findstr
nicht erfolgreich war, der Gegenpart dazu wäreecho "abc"|findstr "[">nul || echo OK
findstr
nicht erfolgreich, dann echo
.Du hast zwar
findstr /b
inzwischen gefunden, dennoch erneut der Hinweis:echo "%%b:~,1"
"abc:~,1"
, was natürlich keinen Syntaxfehler verursacht, warum auch.Derartige Spielchen gingen nur, wenn
set "Var=%%b"
echo "%Var:~,1%" BZW echo "!Var:~,1!"
Das mit dem Lesezugriff ist eine gute Frage, ich nehme an, dieser beginnt beim ersten
findstr
und endet nach der Schleife, ganz sicher bin ich mir jedoch nicht, als anderes Beispiel kann ich dir aber z.B. aufzeigen:echo Text>%datei%
echo Text2>>%datei%
echo Text3>>%datei%
(echo Text
echo Text2
echo Text3)>%datei%
Was passiert, wenn die Batch abschmiert, ganz einfach: Dann gibt es keinen Zugriff auf die Datei und sie ist somit nicht in Benutzung, also geschlossen.
greetz André
edit: Es ging irgendwo noch um eine Pipe? Ich sag's ja: Zu viel Text vor'm Frühstück
Hallo Leopold!
Nur ganz kurz wegen des "|": Wie Du schon festgestellt hast, wird das Pipe-Symbol vom System verwendet (bzw speziell interpretiert) - daher kannst Du es nicht einfach per
ausgeben, sondern musst es mit "^" maskieren oder unter Anführungszeichen setzen.
Tatsächlich ginge es aber in diesem Fall trotzdem, nur den Anfang der Zeile zu überprüfen - es müsste eben das Anführungszeichen am Anfang in die "
Ich würde aber trotzdem ein anderes Trennzeichen (eher "harmlos" wären zB
Grüße
bastla
Nur ganz kurz wegen des "|": Wie Du schon festgestellt hast, wird das Pipe-Symbol vom System verwendet (bzw speziell interpretiert) - daher kannst Du es nicht einfach per
echo 1|2|3
Tatsächlich ginge es aber in diesem Fall trotzdem, nur den Anfang der Zeile zu überprüfen - es müsste eben das Anführungszeichen am Anfang in die "
findstr
"-Suche einbezogen (und dafür innerhalb des Suchstrings verdoppelt) werden - fördert zwar die Nachvollziehbarkeit nicht, sollte aber funktionieren:echo "%%b"|findstr /b """[">nul && set "InSection="
§$#_
) verwenden ...Grüße
bastla
Zitat von @Leopold.Bloom:
noch mal vielen Dank für Euren großen Einsatz. Seid Ihr eigentlich Profi Supporter oder macht Ihr das in Eurer Freizeit?
*hust* Wenn ich nach 18 Uhr schreibe, mach ich es in der Freizeit, sonst ist es eigentlich meine Arbeitszeit, wo ich arbeiten sollte aber wenn man mal Luft hat ...noch mal vielen Dank für Euren großen Einsatz. Seid Ihr eigentlich Profi Supporter oder macht Ihr das in Eurer Freizeit?
@Skyemugen
Tut mir leid, wenn ich geschwätzig war - ich habe immer Sorgen, dass ich sonst mein Anliegen nicht klar genug formuliert kriege. Und dass meine Fragen sicher schon mal gestellt wurden, kann ich mir lebhaft vorstellen. Jeder der mit dieser Art Programmierung anfängt, wird auf die gleichen Probleme oder ähnliche stoßen. Das geht mir mit SQL und anderen Sprachen nicht anders. Nur, dass ich da oft die Fragen beantworten kann.
Tut mir leid, wenn ich geschwätzig war - ich habe immer Sorgen, dass ich sonst mein Anliegen nicht klar genug formuliert kriege. Und dass meine Fragen sicher schon mal gestellt wurden, kann ich mir lebhaft vorstellen. Jeder der mit dieser Art Programmierung anfängt, wird auf die gleichen Probleme oder ähnliche stoßen. Das geht mir mit SQL und anderen Sprachen nicht anders. Nur, dass ich da oft die Fragen beantworten kann.
Wer hat etwas von geschwätzig geschrieben? Es war nur ungewohnt Wir sind immer froh, wenn Leute nicht nur herkommen, um c&p die Lösung vorgesetzt zu bekommen, sondern selbst etwas lernen, hey ich habe Rumbätscheln auch erst mit/bei Administrator.de gelernt.
Gerade lieber etwas genauer beschrieben als eine unklare Anfrage, wie wir sie zu 80% im Batch-Bereich haben.
greetz André