1

I am not able to understand why zsh is generating the same random value when calling a subshell.

Consider the following code:

$ cat script.sh
#!/bin/zsh

checkFieldConvergence () {
  echo $RANDOM
  echo $RANDOM
}

echo $(checkFieldConvergence)
echo $(checkFieldConvergence)
echo $(checkFieldConvergence)
checkFieldConvergence
checkFieldConvergence
checkFieldConvergence

$ ./script.sh
4049 24768
4049 24768
4049 24768
4049
24768
20764
3330
17114
1195

whereas the same with bash gives

$ cat script.sh
#!/bin/bash

checkFieldConvergence () {
  echo $RANDOM
  echo $RANDOM
}

echo $(checkFieldConvergence)
echo $(checkFieldConvergence)
echo $(checkFieldConvergence)
checkFieldConvergence
checkFieldConvergence
checkFieldConvergence

$ ./script.sh
12274 28155
27609 10269
14100 14662
6945
17897
20354
29817
14495
27552
manolius
  • 395
  • 3
  • 15

1 Answers1

2

why zsh is generating the same random value when calling a subshell

Bash detects if it's run in the subshell and if it is, bash re-seeds the random generator using the current value of gettimeofday(), while Zsh does not re-seed the generator and just calls rand().

References: https://github.com/bminor/bash/blob/f3a35a2d601a55f337f8ca02a541f8c033682247/variables.c#L1371 , https://github.com/bminor/bash/blob/f3a35a2d601a55f337f8ca02a541f8c033682247/lib/sh/random.c#L87 vs https://github.com/zsh-users/zsh/blob/00d20ed15e18f5af682f0daec140d6b8383c479a/Src/params.c#L4294 .

For a truly random number different between sub-shells, use SRANDOM.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Regarding SRANDOM, I see this is shipped with new BASH 5.1 and that can be installed externally: for example [in Ubuntu](https://askubuntu.com/questions/1318851/how-to-make-the-more-random-random-replacement-srandom-available-on-ubuntu). Some people is using srand() [in AWK](https://unix.stackexchange.com/questions/424715/bash-how-to-generate-random-float-number-using-random). But I can't find anything on Zsh. Is there an alternative way of changing the seed within Zsh? I could change the seed in the function definition, for example – manolius Jul 01 '21 at 20:05
  • The good old `cat /dev/urandom | ....` like https://stackoverflow.com/a/1195035/9072753 – KamilCuk Jul 01 '21 at 20:13
  • Thanks for the help – manolius Jul 01 '21 at 20:20
  • For future visitors, from the link provided by KamilCuk the best _practical_ command using `/dev/urandom` is not in the most voted answer, and it is `od -A n -t d -N 1 /dev/urandom |tr -d ' '` – manolius Jul 01 '21 at 20:31
  • @manolius: I'm seeding the random generator randomly in my `.zshrc` by doing a `RANDOM=$(($(od -vAn -N2 -tu2 < /dev/urandom)))`. If you want to do this also for non-intaractive shells, do it in `.zshenv` instead. – user1934428 Jul 02 '21 at 09:39