On Mon, May 20, 2024 at 12:14 PM Kannan Varadhan <kvaradhan3@gmail.com> wrote:

On 5/20/24 11:01, Roman Perepelitsa wrote:

On Mon, May 20, 2024 at 7:41 PM Kannan Varadhan <kvaradhan3@gmail.com> wrote:
     while (( $#bytes < 4 )); do
       sysread -s$((4-$#bytes)) 'bytes[$#bytes+1]' </dev/urandom || return
     done
Reading 1 byte at a time is slower than reading 4 bytes at once.

ok but the loop seems to read 4, then 3, 2, and 1B in each iteration, or did I miss something?


To clarify this, it has to do with the way sysread assigns to the parameter 'bytes[$#bytes+1]'.

On the first iteration, $#bytes == 0, so this is 'bytes[1]'.  Assignment to a subscripted parameter reference replaces the element at the subscript position (or positions, if a range is given, which is not allowed for associative arrays) with the assigned value.  Thus all bytes returned from /dev/urandom in the first read are inserted in place of position 1 in the string bytes.  There's nothing at position 1 yet in this case, so that becomes the entire value of $bytes.  If fewer than 4 bytes were returned -- say, 2 -- then at the next iteration we sysread into bytes[3], which is past the end of the existing 2-byte value, so has the effect of appending the next series of bytes and lengthening the string.

Upshot:  The loop attempts to read the exact number of (remaining) bytes necessary to fill a four-byte string, and repeatedly appends if and only if it doesn't yet have all four.