This is a strange behavior I can't explain. I want to use shell to generate a predictable random number sequence. I use $RANDOM with a seed. Here is a test program.
RANDOM=15
echo $RANDOM
This works fine by giving the same number every time I run it. But if I add a pipe to this program it gives different results every time. Try the following simplified program.
RANDOM=15
echo $RANDOM | cat
I have found 2 fixes to the problem (making it predictable), but still can't explain why.
Fix 1
RANDOM=15
x=$RANDOM
echo $x | cat
Fix 2
(RANDOM=15
echo $RANDOM) | cat
I tried on Linux and Mac. The behavior is consistent. Can somebody explain?
Pipelines, as in echo $RANDOM | cat
, create subshells -- separate processes forked from the parent but not replaced with a different executable image using an exec()-family call. You're observing a difference in behavior between the shell in which RANDOM
is explicitly set, and subshells forked from same.
Your workarounds either move the evaluation of $RANDOM
out of a subshell into the parent (first case), or move the explicit seed set into the subshell (second case).
Thank you Charles Duffy for pointing to the right direction (subshell). I found in the src code of bash, there is file variable.c . $RANDOM is a "dynamic variable", to get the value a function is called; and the function re-seeds the random generator when $RANDOM is first evaluated in the subshell.
// from bash-4.3/variables.c
int
get_random_number ()
{
int rv, pid;
/* Reset for command and process substitution. */
pid = getpid ();
if (subshell_environment && seeded_subshell != pid)
{
seedrand (); // <<<<==== re-seed!
seeded_subshell = pid;
}
do
rv = brand ();
while (rv == last_random_value);
return rv;
}
Seed is a static variable, so each shell has its own copy. Re-seeding in the subshell has no effects in the parent. Here is another test case to show $RANDOM reference in subshell has nothing to do with the sequence in parent shell.
RANDOM=15
echo $RANDOM $RANDOM
RANDOM=15
echo $RANDOM | cat
echo $RANDOM
The last line gives the first random number after 15.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With