[Toybox] Would someone please explain what bash is doing here?

Chet Ramey chet.ramey at case.edu
Thu Apr 2 15:07:01 PDT 2020


On 3/31/20 10:23 AM, Rob Landley wrote:

> Did you know that when RANDOM is exported, the readonly attribute is ignored
> (but prserved!) in a DIFFERENT way?

How so? The example doesn't really show that.

> $ readonly RANDOM
> $ export RANDOM=0
> $ echo $RANDOM
> 24315
> $ export RANDOM=42
> $ echo $RANDOM
> 11151
> $ declare -p RANDOM
> declare -irx RANDOM="23481"
> $ RANDOM=42
> $ echo $RANDOM $RANDOM
> 17766 11151
> 
> Now the assignment goes through, and THEN it errors, I.E. the line is still
> aborted, but for no obvious reason since the assignment was successful!

I think I covered this in my last message.

> (Also, exporting resolves the variable once after assigning it, so instead of
> giving the reset value it gives the resolved magic value, and the sequence
> continues from there. Eh, I suppose that makes sense?)

Yes. The idea is that `export RANDOM=42' and `RANDOM=42 ; export RANDOM'
have identical behavior and semantics. POSIX has more-or-less tried to
specify this.

> 
> Also, calling declare -p RANDOM re-exports the current value?
> 
> $ echo $RANDOM $RANDOM
> 17766 11151
> $ declare -p RANDOM
> declare -irx RANDOM="23481"
> $ declare -p RANDOM
> declare -irx RANDOM="32503"
> $ env | grep RANDOM
> RANDOM=32503
> $ env | grep RANDOM
> RANDOM=32503
> 
> but merely resolving it doesn't?

The environment doesn't get recreated after every builtin or every
reference to a dynamic variable. That hasn't been a problem so far.

> 
> $ RANDOM=42
> $ echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM
> 17766 11151 23481 32503 7018 25817 28529
> $ echo $RANDOM
> 9160
> $ env | grep RANDOM
> RANDOM=9160
> $ echo $RANDOM
> 16666
> $ env | grep RANDOM
> RANDOM=9160
> 
> Ah, no, that's not what's happening:
> 
> $ export RANDOM=42
> $ env | grep RANDOM
> RANDOM=17766
> $ declare -p RANDOM
> declare -ix RANDOM="11151"
> $ env | grep RANDOM
> RANDOM=17766
> 
> The actual export is deferred until the first non-builtin is called (echo is a
> builtin), but is then persistent. And the $RANDOM value is CACHED somehow?

I explained this earlier.

> (Notice how declare showed the value that THEN wound up in the environment?)
> 
> $ export RANDOM=42; echo $RANDOM; env | grep RANDOM
> 11151
> RANDOM=11151
> $ export RANDOM=42; echo $RANDOM $RANDOM; env | grep RANDOM
> 11151 23481
> RANDOM=23481
> 
> Um, what?

What's the problem? The environment gets created with the current value of
the variable.

> 
> $ export RANDOM=42; env | grep RANDOMRANDOM=17766
> $ export RANDOM=42; echo $RANDOM $RANDOM $RANDOM
> 11151 23481 32503
> $ export RANDOM=42; echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM
> 11151 23481 32503 7018 25817 28529
> $ export -n RANDOM
> $ RANDOM=42; echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM
> 17766 11151 23481 32503 7018 25817
> 
> So wait, exporting it resolves the value once but doesn't actually put the
> resolved value into the ENVIRONMENT because that's deferred to exec time?

Exporting a variable doesn't do anything but look up the variable and set
an attribute. Just like declaring a variable readonly or integer. The
effect is only seen on subsequent commands.

> To be honest, the behavior of BOTH $SECONDS and $RANDOM is insane enough I kinda
> dowanna exactly match it? 

OK.

> And RANDOM... I understand wanting a repeatable sequence of pseudo-random
> numbers, but I dunno what prng they're using so I can't get the SAME sequence
> (ltrace isn't catching anything with "rand" in the name and I refuse to look at
> GPLv3 source code and potentially open myself to insane
> https://lwn.net/Articles/193852/ style lawsuits).

That is, of course, your choice. You could look at the bash-3.2
implementation, since that is the last GPL2 release.


> P.S. Why is $GROUPS an array? If you just resolve $GROUPS you get $(id -g) but
> wouldn't it make more sense since it's PLURAL for it to be $(id -G) since it's
> NUMERIC and we have FOR LOOPS? 

This doesn't really make any sense. GROUPS is an array because people are
in multiple groups, and arrays are a natural way to manage those. If you
want to deal with groups individually, and you don't use arrays, you have
to do more work that arrays give you for free. Since your primary group is
in ${GROUPS[0]}, referencing $GROUPS give you your primary group in a
painless fashion.

If you don't have arrays, you're not constrained by bash's builtin array
variables anyway.

Chet

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
		 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    chet at case.edu    http://tiswww.cwru.edu/~chet/



More information about the Toybox mailing list