# How do I create a loop of variable length to print random numbers?

I'm trying to create a matrix of random numbers after prompting the user for the number of rows and columns of random numbers. I can only use nested for loops.

I have created two variables: rows and columns but my main problem is getting the for loop to echo properly. Here's my loop function

``````    for i in [1..\$rows]; do
echo "\$RANDOM";
done
``````

I have tried to increment the value of i with 1+1 but not matter what it only runs the loop once. I want the script to read the value of \$rows.

• How will you use the random numbers? If you want to use them where it is critical that they are good random numbers and not predictable from a simple pseudo-random generator, you should not use `RANDOM` but `/dev/urandom`. See `man urandom`. (Examples of critical usage: to generate passwords or encryption keys.) May 4 '20 at 12:45

There is no syntax like `[x..y]`. You're probably thinking of `{x..y}`, but that doesn't work if either `x` or `y` are variables.

So, you could try one of these instead:

``````for((i=1;i<=\$rows;i++)); do
echo "\$RANDOM"
done
``````

Or

``````for i in \$(seq 1 "\$rows"); do
echo "\$RANDOM"
done
``````

Or

``````i=0
while (( ++i <= rows)); do
echo "\$RANDOM";
done
``````

Or even

``````i=0
until [ \$i -gt \$rows ]; do
echo "\$RANDOM"
((i++))
done
``````
• Perhaps use the arithmetic conditional `while (( ++i <= rows))` May 5 '20 at 12:30
• @glennjackman done, thanks. Is there any benefit to that apart from being slightly shorter than my `while [ \$((i++)) -le \$rows ]`? It does feel more elegant, but is there some other consideration as well?
– terdon
May 5 '20 at 12:52
• Aside from the nicer syntax (less punctuation implies fewer errors), this protects you from some values of \$rows: if rows is unset or empty, it gets value zero in arithmetic (with no `\$`) -- unset or empty variable unquoted in brackets gives a syntax error (All variables in `[...]` should be quoted to protect from word splitting, filename expansion). May 5 '20 at 15:54
• @glennjackman very good points, thanks.
– terdon
May 5 '20 at 16:57

As terdon pointed out, the syntax you use is not correct, and he went on to give a few examples of loops that would work.

However, to print `\$rows` number of random integers, you may also use

``````jot -r "\$rows"
``````

or, equivalently,

``````jot -r "\$rows" 1 100
``````

which will output `\$rows` random integers between 1 and 100 inclusively (`jot` is available on BSD systems, or in the `athena-jot` package on some Linux systems).

Or,

``````shuf -i 1-100 -r -n "\$rows"
``````

which will do the same as the `jot` command above (`shuf` is part of GNU coreutils).

To create a matrix of `\$cols` times `\$rows` entries, you could use `rs` (`rs` is available on BSD systems, or in the `rs` package on some Linux systems):

``````\$ rows=4
\$ cols=6
\$ jot -r "\$(( rows * cols ))" | rs "\$rows" "\$cols"
37  29  2   74  5   14
82  86  74  63  73  9
58  10  14  96  12  90
98  13  55  56  40  52
``````

Note that we need `\$rows * \$cols` random numbers. The example used here gets these from `jot`, but `shuf` could also be used (or any other command that produces the numbers).

With `zsh`:

``````\$ eval print -C4 '\$(('{1..20}', RANDOM))'
11190  17138  16156  5735
16751  13545  22647  13244
12925  11584  10984  32387
32093  8170   5305   6102
25136  30299  3944   9956
``````

Or using GNU `shuf` to specify the range:

``````\$ print -C4 \$(shuf -i 0-99 -n 20)
96  55  93  33
25  7   19  60
34  51  88  46
79  13  70  98
63  37  69  41
``````