$RANDOM auf der ZSH kaputt!?

SierraX

Well-Known Member
Aus Gründen hab ich versucht in 10 Subnetzen je bis zu 25 zufällige IP's erstellen zu lassen… so weit so unspektakulär…
Code:
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM % 255 ));done;done | sort
Ich hatte mit dann gewundert, dass , wenn ich die liste uniq machen wollte, die Anzahl der Zeilen von run zu run immer gleich blieb.
Bei weiteren Tests ist mir dann aufgefallen, das nur die Verteilung unterschiedlich war (in dem ich das sort einfach weg gelassen habe).
Ich bin zuerst von Hardware Seite ausgegangen… ein Digital Computer tut sich halt ein wenig schwer damit ein Random ein wenig zu salzen… kennt man ja auch vom Arduino. Komischerweise sind Bourne-shell, bash und ksh allerdings nicht davon betroffen.

Code:
zsh
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t1.txt
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t2.txt
diff t1.txt t2.txt | wc -l
       0
bash
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t1.txt
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t2.txt
diff t1.txt t2.txt | wc -l
     498
ksh
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t1.txt
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t2.txt
diff t1.txt t2.txt | wc -l
     497
sh
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t1.txt
for i in $(jot 10); do for j in $(jot 25); do echo 192.168.$(( 100 + i)).$(( 1 + $RANDOM  % 255 ));done;done | sort > t2.txt
diff t1.txt t2.txt | wc -l
     494

Hatte dann noch überlegt, ob auf meinem OpenBSD das KSH vielleicht ein wenig zu alt ist… da sich das aber auf einem MBP-i9 mit Catalina und einem MM-M1 mit Big Sure reproduzieren liess… wird das wohl auch nicht der Grund sein.

Hat hier schonmal jemand von diesem Problem oder Feature gehört?
 
$(( 1 + $RANDOM % 255 )) ruft eine Subshell auf, bei der zsh hat $RANDOM in Subshells immer den gleichen Seed. Daher ergibt sich jedes mal die gleiche Sequenz. Um das zu umgehen, musst du $RANDOM vor jedem Aufruf der Subshell innerhalb der Parent Shell einen Seed zuweisen oder es dort mindestens einmal referenzieren.
 
$(( 1 + $RANDOM % 255 )) ruft eine Subshell auf

Seit wann denn das?

Edit: Ich löse mal auf: Die Subshell entsteht dadurch, dass du Pipes nutzt. Wenn du die for-Schleife einfach so ausführst, erhältst du immer ein anderes Ergebnis. Ein
Code:
: $RANDOM
vor die for-Schleife reicht, um auch mit Pipe immer andere Ergebnisse zu erhalten.
 
Zuletzt bearbeitet:
Edit: Ich löse mal auf: Die Subshell entsteht dadurch, dass du Pipes nutzt. Wenn du die for-Schleife einfach so ausführst, erhältst du immer ein anderes Ergebnis. Ein
Code:
: $RANDOM
vor die for-Schleife reicht, um auch mit Pipe immer andere Ergebnisse zu erhalten.
So ganz verstehe ich das immer noch nicht. Und die Ergebnisse sind auch mit : $RANDOM bei einem kleineren Test ohne Integer Arithmetic etwas unbefriedigend:

Code:
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
10654
15381
17475
19710
7557
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
10654
11643
15381
17475
19710
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
11643
15381
17475
19710
5122
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
11643
15381
17475
5122
7940
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
11643
16544
17475
5122
7940
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
11643
16544
28946
5122
7940
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
16544
27337
28946
5122
7940
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
16544
21353
27337
28946
7940
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
16544
20958
21353
27337
28946
➜  ~ : $RANDOM; for i in {1..5}; do echo $RANDOM;done | sort
20958
21353
25886
27337
28946
 
Du musst das : $RANDOM mit der kompletten Schleife klammern, sonst wird es nicht im Prozess ausgeführt der die Ausgabe in die Pipe macht.
 
Zurück
Oben