132. Nachfage eines Lesers:  Zufallsverteilung  von  Variablen in einem For-Befehl

Einleitung

Die Sternenhimmelstuermerseite ruhte, aber eine Nachfrage  zu  einer Batch seines Projektes NoNSA, reaktiviert diese Seite für einen weiteren Artikel. Der Sternenhimmelstuermer verlor bei seinen Großprojekten ein wenig die Erklärung einzelner Befehle aus den Augen. Sorry, aber bei Großprojekten wie seiner Desktopsuchmaschine mit um die 500 Zeilen Code ist  das leider so nicht mehr möglich.

Da die Sternenhimmelstuermer-Tipps mit Nummern chronologisch versehen sind, findet man meistens  Beschreibungen von Code-Teilen ein paar Abhandlungen zuvor. Die Befehlsketten und der Stil eines Autors, der sich daraus ergibt, sind auf der Sternenhimmelstuermerseite gut nachvollziehbar. Wie dem auch sei - bei der Zufallsausgabe von Variablen in einem For-Befehl gibt es keine vorherige Beschreibung.

Inhaltsangabe
Basis zwei Batches und ein Textdokument
Erklärung -Batch2 mit For-Befehl zum Austausch von Reihen in Tabelle per Zufall Schritt für Schritt
Erklärung: Rücktausch der nach Zufall getauschten Reihen

Basis zwei Batches und ein Textdokument


Zur Erinnerung noch einmal den Code (ist jetzt aus zwei Batches des Projektes Babel zusammengeführt, aber in einer Batch lauffähig - einfach die beiden Codeblöcke in blauer Schrift in eine Batch kopieren und an beliebigen Standpunkt ausführen):

Batch1.bat

Rem die horizontalen Drehungen werden durchgefuehrt nach Zufallsblocktexten
if exist block_*_*.log (goto los) else goto generate

:generate
set /a z=0
:Schleifeblock
if %z% GEQ 12 goto los
set /a z=%z%+1
:newnumber
SET MIN=1
 SET MAX=12
 SET /a Zufallszahl=MIN+(MAX-MIN+1)*%random%/32768
If exist block_*_%Zufallszahl%.log (goto newnumber) else echo %z% %Zufallszahl% >block_%z%_%Zufallszahl%.log
goto Schleifeblock
:los

:chiffreexist


Bis hierher wurden einfach nur zwölf Log-Dokumente mit Zufallszahlen erstellt. Dieser Codeteil wurde bereits mehrfach erklärt. Bei Nachfragen in folgenden Link nachschauen.  Wichtig sind nur die Zahlen der Überschriften in den Log-Dokumenten, der Inhalt spiegelt die Überschrift nun wieder....


Batch2.bat

REM zufallszahll bestimmt Drehung aller zwoelf Buchstabenreihen

set destination=%~dp0%
set /a y=0
:loopb
if %y% geq 12 goto loopbende
set /a y=%y%+1
if exist block_1_%y%.log echo i >>var1%y%.txt
if exist block_2_%y%.log echo j >>var1%y%.txt
if exist block_3_%y%.log echo k >>var1%y%.txt
if exist block_4_%y%.log echo l >>var1%y%.txt 
if exist block_5_%y%.log echo m >>var1%y%.txt
if exist block_6_%y%.log echo n >>var1%y%.txt
if exist block_7_%y%.log echo o >>var1%y%.txt 
if exist block_8_%y%.log echo p >>var1%y%.txt  
if exist block_9_%y%.log echo q >>var1%y%.txt
if exist block_10_%y%.log echo r >>var1%y%.txt 
if exist block_11_%y%.log echo s >>var1%y%.txt 
if exist block_12_%y%.log echo t >>var1%y%.txt
goto loopb
:loopbende


set /p var1=<var11.txt
set /p var2=<var12.txt
set /p var3=<var13.txt
set /p var4=<var14.txt
set /p var5=<var15.txt
set /p var6=<var16.txt
set /p var7=<var17.txt
set /p var8=<var18.txt
set /p var9=<var19.txt
set /p var10=<var110.txt
set /p var11=<var111.txt
set /p var12=<var112.txt
>"%destination%codeblock1.bat"   ECHO FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims= " %%%%i IN (chif.txt) DO echo %%%%%var1% %%%%%var2% %%%%%var3% %%%%%var4% %%%%%var5% %%%%%var6% %%%%%var7% %%%%%var8% %%%%%var9% %%%%%var10% %%%%%var11% %%%%%var12% ^>^>chifende.txt
>>"%destination%codeblock1.bat"  ECHO exit ^>^>chifende.txt
start /wait codeblock1.bat
del var*.txt
del chif.txt
del codeblock1.bat


Dann brauchen Sie noch ein Textdokument mit Namen chif.txt Da können dann Zwölf Buchstaben mit Seperator Leerzeichen (beliebig viele Reihen) sein:

Z. B.

a b c d e f g h i j k l m n o p q r s t
t s r q p o n m l k j i h g f e d c b a

und/oder...

Reihe1 Reihe2 Reihe3 Reihe4 Reihe5 Reihe6 Reihe7  Reihe8 Reihe9       Reihe10 Reihe11    Reihe12
das      ist        so        egal      nur       zwoelf Woerter mit      leerzeichen als          Seperator  ok

Vielleicht einfach nur die a - t Reihe allein? Für das Verständnis reicht das...

Das muss jetzt nicht mit zwei oder drei Leerzeichen sein. Sie kenn das vielleicht aus *.csv-Dateien. Separatoren müssen in diesem Fall Leerzeichen sein.

Wer den For-Befehl ein wenig kennt, weiß dass  Separatoren als delims bezeichnet werden:

"delims= "
ist also ein Leerzeichen als Separator.
delims=,"  ist ein Komma als Separator
 delims=: "  ist ein Doppelpunkt als Seperator
delims=" heißt, dass es überhaupt keine Trennung gibt...Die ganze Zeile ist %i

Und dann gibt es für kreative Menschen Mischformen wie Doppelpunkt und Leerzeichen. Wenn Sie z. B. Zuvor Zeilennummern vergeben haben, wie z. B. 1:  eins zwei.  Probieren Sie es mal aus meistens klappt es zusammen mit dem tokens Befehl, in diesem Fall tokens 1,2,3...


Sieht zugegebener Maßen erstmal schwer aus, aber ist gar nicht so schwer, wenn man das System versteht und vernünftig erklärt bekommt. Ziel ist es, dass eine Reihe in einem beliebig langen Text  (oder genauer gesagt Tabelle) per Zufall Zeilen getauscht werden.




Erklärung Schritt für Schritt.

Die 12 Dokumente mit der Nummerierung block_1_Zufallszahl.log bis block_12_Zufallszahl.log liegen also erstmal nach Betätigung der  Batch1.bat vor. Für Zufallszahl stellen Sie sich eine Zahl von 1-12 vor, z. B.  block_1_6.log.

Das ist unsere Arbeitsgrundlage für Batch2.bat. Die wird jetzt Schritt für Schritt erklärt:

set destination=%~dp0%

Der Standort der Batch wird ermittelt. Der Pfad kriegt den Variablennamen destination.

set /a y=0
:loopb


Eine Variable Y vor dem Beginn einer Schleife bekommt den Zahlwert 0 zugeordnet. Den werden wir niemals brauchen. Aber in der folgenden Schleife wird dieser Wert dann bei jedem Schleifendurchgang um die Zahl 1 erhöht, bis dann in diesem Fall eine 12 erreicht wurde. Dann endet die Schleife. Das können Sie hier noch nicht erkennen.

Der Anfangspunkt einer Schleife mit Goto hat immer einen Doppelpunkt und dann ein frei wählbares Wort. Vorsicht! Verwenden Sie in einer  Batch  zweimal dasselbe Schleifenwort, dann springt die Batch garantiert zum falschen Schleifenpunkt und es kommt Müll heraus. Deshalb verwendet der Sternenhimmelstuermer ein sinniges Wort gepaart mit  irgendeinen Buchstaben oder wechselt von deutsch zu englisch...

if %y% geq 12 goto loopbende
set /a y=%y%+1


Das ist schon der angekündigte Ausstieg aus der Schleife ( if %y% geq 12 goto loopbende ) Nach zwölf durchläufen von y ist 12 =12 und die Schleife ist beendet. Danach kommt die vorhin schon angekündigte Erhöhung von y um den Wert 1. Beim 5 Schleifendurchlauf kommt der if - Befehl nicht zur Geltung. Y wird um eine 1 erhöht und ist nun 6. Es werden also noch einmal die folgendenden Befehle abgearbeitet:

if exist block_1_%y%.log echo i >>var1%y%.txt
if exist block_2_%y%.log echo j >>var1%y%.txt
if exist block_3_%y%.log echo k >>var1%y%.txt
if exist block_4_%y%.log echo l >>var1%y%.txt 
if exist block_5_%y%.log echo m >>var1%y%.txt
if exist block_6_%y%.log echo n >>var1%y%.txt
if exist block_7_%y%.log echo o >>var1%y%.txt 
if exist block_8_%y%.log echo p >>var1%y%.txt  
if exist block_9_%y%.log echo q >>var1%y%.txt
if exist block_10_%y%.log echo r >>var1%y%.txt 
if exist block_11_%y%.log echo s >>var1%y%.txt 
if exist block_12_%y%.log echo t >>var1%y%.txt
goto loopb


Wenn also ein block_1_6.log Dokument vorliegt, dann wird der Buchstabe i ausgegeben if exist block_1_%y%.log echo i >>var1%y%.txt . Das ganze wird im Beispiel in ein Dokument mit dem Namen var16.txt geschrieben. Das ist in unserem Beispiel der Fall.

Verstehen Sie richtig: Wir wissen, dass die Werte von Y 1-12 annehmen können. Also egal, welche Zufallszahl von 1- 12 im block_1_y.log steht, irgendwann steht im var1%y%.txt der Buchstabe i.
Es gibt also in jedem Schleifwndurchgang einen Treffer.

Nehmen wir mal an, dass Dokument block_2_4.log liegt vor. Die vier ist also die eigentlich wichtige Zufallszahl. Nach  dem ersten Schleifendurchgängen nimmt y die Zahl 2 an. Dann wird in der Befehlszeile   if exist block_2_%y%.log echo j >>var1%y%.txt  ein j ausgegeben. In das Dokument var12.txt.

goto loopb Ist das Schleifenende. Der goto Befehl lässt lediglich die Bearbeitung wieder zum nächsten Durchlauf am Anfang springen. Es wird geprüft, ob y 12 erreicht hat, wenn nicht wird y um einen Zahlwert erhöht...bis irgendwannn y=12 ist und der Befehl ( if %y% geq 12 goto loopbende ) aktiv wird und die Schleife beendet, in dem zur Zeile:

:loopbende

gesprungen wird.

set /p var1=<var11.txt
set /p var2=<var12.txt
set /p var3=<var13.txt
set /p var4=<var14.txt
set /p var5=<var15.txt
set /p var6=<var16.txt
set /p var7=<var17.txt
set /p var8=<var18.txt
set /p var9=<var19.txt
set /p var10=<var110.txt
set /p var11=<var111.txt
set /p var12=<var112.txt


Das ist nur so eine Technik des Sternenhimmelstuermers. Jeder Buchstabe in den Textdokumenten wird in einer Variable var1-112 aus den Textdokumenten gespeichert. Wir wissen, dass die Textdokumente var1, var2...var112 vorliegen, aber nicht, welcher Buchstabe sich in den Dokumenten befindet. In unserem Beispiel mit block_1_6.log ist also ein Textdokument mit var16 entstanden (weil die var1 in Kombination mit einer 6 nun mal 16 ergibt. Da der Sternenhimmelstuermer die Grundvariable var1 benannte, ist das erstmal etwas komplizierter. Das y dahinter wird zur 6 in diesem Fall .

In unserem Beispiel mit der Zufallszahl 6 ist var16.txt  also nun var6.  In dem steht bekanntlich ein Buchstabe  i.

>"%destination%codeblock1.bat"   ECHO FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims= " %%%%i IN (chif.txt) DO echo %%%%%var1% %%%%%var2% %%%%%var3% %%%%%var4% %%%%%var5% %%%%%var6% %%%%%var7% %%%%%var8% %%%%%var9% %%%%%var10% %%%%%var11% %%%%%var12% ^>^>chifende.txt
>>"%destination%codeblock1.bat"  ECHO exit ^>^>chifende.txt


Wenn Sie das Vorspiel verstanden haben, dann werden Sie die nächften Zeilen verstehen. Es wird eine Batch erstellt, die eine zugegebener maßen schwierige Zeilen beinhaltet. Gehen wir den Befehl mal stückweise durch:  

>"%destination%codeblock1.bat"   ECHO

Bis hierher erstmal einfach: Es wird eine Batch mit paraller Lage zur Ursprungsbatch gebildet: destination war die die Variabel für den Pfad, die wir zuvor definiert hatten. Es wird die erste Zeile einer Batch namens codeblock1.bat ausgegeben.
Nach dem echo kommt unser Befehl. Aber wozu brauchen wir eine Batch überhaupt?

Um die gerade erzeugten Variablen var1 bis var12 durch reale Buchstaben zu ersetzen. Erst dadurch können die Variablen des For-Befehls ausgetauscht werden.

Denn in einem For-Befehl können wiederum nur die Variablen %%i - %%t bei 12 Zufallszahlen verwendet werden. Vielleicht erstmal eine Tabelle wie ein Austausch von Reihen sich in einer Tabelle aiswirkt:
Stellen Sie sich mal eine kleine Tabelle vor:

Vorname     Name                             Adresse
Manfred     Sternenhimmelstuermer     Berlin
%i               %j                                    %k

I,J und K entsprechen den üblichen Bezeichnungen im For-Befehl! In der cmd mit einem Prozentzeichen, in einem For-Befehl in einer Batch immer zwei Prozentzeichen bei der Ausgabe...

Seperatoren sind Leerzeichen. Per zufälligen vertikalen Tausch könnte dann herauskommen:

Adresse     Name                             Vorname
Berlin         Sternenhimmelstuermer     Manfred
%k           %j                                    %i

Hier wurden mehrere Leerzeichen verwendet, damit das übersichtlicher wird.

Zurück zu den nächsten Teilen des For-Befehls: FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims= " Das heißt nur, das in die Batch wörtlich folgender Text geschrieben wird, der aus Zwölf Bestandteilen (tokens) mit Leerzeichen (delims) besteht.
%%%%i IN (chif.txt) DO echo %%%%%var1%

Zwei der Prozentzeichen beim %%i sind einfach dem Umstand geschuldet, dass in der neuen Batch ein %%i stehen soll. Weiterhin soll in der Batch wörtlich stehenm dass in einem Textdokument namens chif.txt do echo also ausgegeben wird, was dann folgt:

%%%%%var1%

In der Batch müssen hier zwei Prozentzeichen und und ein Buchstabe von i-t bei zwölf Bestandteilen in der Tabelle sein, die durch einen Separator getrennt sind. %%%% sind erstmal zwei Prozentzeichen in der neuen Batch. Die beiden Prozentzeichen vor und nach var1 sind nur die Umrahmung der Variable var1, die in der Batch zu einem Buchstaben werden. Zu welchen Buchstaben? Das weiß leider nicht einmal der Sternenhimmelstuermer, weil es durch den Zufall bestimmt wird.

Er kann es ihnen aber anhand eines praktischen Beispiels mit fiktiven Zahlen verdeutlichen:

Sie erinnern sich?  Es wurde eine Zufallszahl generiert. Die wurde z. B. in ein block_6_1. log geschrieben, wobei die 6 gleich y und 1 der Zufallszahl entspricht. Nachdem diese Datei durch eine Schleife geschickt wurde, steht im var11.txt also ein n ( if exist block_6_%y%.log echo n >>var1%y%.txt ). 

Dieser wird durch die Zeile set /p var1=<var11.txt  zur Variablen var1, also zum festgelegten Buchstaben n

In der Batch steht also bis hierher: FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims= " %%i IN (chif.txt) DO echo %%n

Aha, wir haben unser Ziel erreicht an der ersten Stelle in der Ausgabe des For-Befehls steht nun ein n statt ein i.

Die folgenden var2, var3....var12 sind absolut dasselbe Spiel. Das ganze wird dann nur noch in ein neues Dokument ausgegeben: ^>^>chifende.txt

Die Karatzeichen sind nur wieder zum escapen der Ausgabezeichen >>.

>>"%destination%codeblock1.bat"  ECHO exit ^>^>chifende.txt

Die Zeile ist ein wenig fehlerhaft - eigentlich sollte die nur den Befehl exit ausgegeben. In das Dokument chifende.txt wird nichts mehr geschrieben. Ist so beim kopieren passiert aber absolut unschädlich...

Es wurde also eine Batch codeblock1.bat generiert, in der im Klartext steht:

FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims= " %%i IN (chif.txt) DO echo %%q  %%o   %%t  %%j  %%m  %%r   %%p    %%s   %%l   %%i  %%n  %%k  >>chifende.txt
exit

Dann wird die Batch gestartet - und darauf gewartet, dass die Reihen gedreht werden
start /wait codeblock1.bat

Danach werden nur noch ein paar Hilfsdokumente zerstört...
del var*.txt
del chif.txt
del codeblock1.bat


Rückdrehung


Wem das noch nicht reicht, der kann nun erfahren, wie man die Reihen wieder zurückdreht. aus diesem Grund wurden die Block_Zahl_Zufallszahl-Dokumente auch nicht geköscht.
Irgendwie müssen wir ja herausbekommen, wie nach dem Zufall die Reihen gedreht wurden...Da hilft uns auch nicht die Batch1.bat mehr, da Sie ja immer neue Kombinationen generiert:

Wir haben also unsere 12 Dokumente und unseren chifende.txt.

Batch3.bat

REM zufallszahl bestimmte Drehung einzelner Buchstabenreihen wird aufgehoben

set destination=%~dp0%
set /a y=0
:loopb1
if %y% geq 12 goto loopbende1
set /a y=%y%+1
if exist block_%y%_1.log echo i >>var2%y%.txt
if exist block_%y%_2.log echo j >>var2%y%.txt
if exist block_%y%_3.log echo k >>var2%y%.txt
if exist block_%y%_4.log echo l >>var2%y%.txt 
if exist block_%y%_5.log echo m >>var2%y%.txt
if exist block_%y%_6.log echo n >>var2%y%.txt
if exist block_%y%_7.log echo o >>var2%y%.txt 
if exist block_%y%_8.log echo p >>var2%y%.txt  
if exist block_%y%_9.log echo q >>var2%y%.txt
if exist block_%y%_10.log echo r >>var2%y%.txt 
if exist block_%y%_11.log echo s >>var2%y%.txt 
if exist block_%y%_12.log echo t >>var2%y%.txt
goto loopb1
:loopbende1


set /p var1=<var21.txt
set /p var2=<var22.txt
set /p var3=<var23.txt
set /p var4=<var24.txt
set /p var5=<var25.txt
set /p var6=<var26.txt
set /p var7=<var27.txt
set /p var8=<var28.txt
set /p var9=<var29.txt
set /p var10=<var210.txt
set /p var11=<var211.txt
set /p var12=<var212.txt
>"%destination%codeblock2.bat"   ECHO FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims= " %%%%i IN (chifende.txt) DO echo %%%%%var1% %%%%%var2% %%%%%var3% %%%%%var4% %%%%%var5% %%%%%var6% %%%%%var7% %%%%%var8% %%%%%var9% %%%%%var10% %%%%%var11% %%%%%var12% ^>^>chifendeergebnis.txt
>>"%destination%codeblock2.bat"  ECHO exit ^>^>chifendeergebnis.txt
start /wait codeblock2.bat
del var*.txt
del chifende.txt
del codeblock2.bat


Sie werden nach dem Studium des vorherigen Kapitels sagen, aber das ist ja fast genau dasselbe. Stimmt, die herangehensweise ist identisch mit einem kleinen (aber wichtigen) Unterschied:

Vergleichen wir die Zeile aus dieser Natch mit der vorherigen:

if exist block_%y%_1.log echo i >>var2%y%.txt 
if exist block_1_%y%.log echo i >>var1%y%.txt

Aha, es wurden  lediglich  in der Y-Schleife die  Y-Zahl (Nummerierungszahl in der ersten Batch von 1 - 12) mit der  Zufallszahl (1-12 in der ersten Batch) ausgetauscht.

Vielleicht ein einfaches Beispiel mit der Nummerierungszahl 1 und der Zufallszahl 6:

block_1_%6%.log
in der ersten Batch. Wir wissen durch das Einsetzen der Zahlen nun, dass i sich  an der sechsten Position, also var6 im For-Befehl befindet.

Wir müssen also die sechste Position wieder an die erste Stelle Rücken. Das ist schon die ganze Erklärung, wenn Sie das letzte Kapitel gelesen und verstanden haben...

Auf der Metaebene sieht das in Variablen schwer aus. Wie gesagt: Selbst der Sternenhimmelstuermer weiß nicht, welche Zahlen sich dahinter verbergen - das ist auch egal, denn hier gilt zu 100 % der Spruch:

Denn das Ziel ist der Weg.

Fazit

Der Sternenhimmelstuermer bleibt keine Erklärung schuldig, insbesondere wenn eine Programiertechnik ein riesiges Potential darstellt. Dahinter steckt nämlich eine Art Abstraktionsprinzip, dass eine kleine Subordination durch den  Zufall erfährt. Der Sternenhimmelstuermer ist bekanntlich der Frankenstein der  Esoteriker  in  der Computerwelt, beseelt mit dem Gedanken  künstliche Intelligenz zu schaffen...

Daran sieht man, dass nicht nur das der Alchimist Böttger das Porzellan als Nebenprodukt entdeckte, sondern bei den Abhandlungen des Sternenhimmelstuermers viele sinnvolle Projekt auf Batchebene realisiert wurden. Der Stein der Weisen wurde hier zwar noch nicht präsentiert, aber die Rückkehr des Sternenhimmelstuermers ist absehbar - mit mächtigeren Programmen als zuvor.

Leider bleiben dann immer mehr Erklärungen auf der Strecke, aber wer das offene Tagebuch (diese Webeite) weiterhin verfolgt, dürfte immer auf dem Stand sein und der Entwicklung folgen können...




Impressum
Datenschutz