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...