فصل 9. یک نگاه دیگر به متغیرها

‎9.3‎‏- ‎$RANDOM‎: تولید عدد صحیح تصادفی

 

هر شخصی که تلاش می‌کند اعداد تصادفی را با روشهای قطعی تولید کند، به طور حتم در اشتباه به سر می‌برد.

‎--John von Neumann‎

‎$RANDOM‎ یک تابع درونی Bash است (نه یک ثابت) که یک عدد صحیح تصادفی ساختگی ‎[1]‎ در محدوده ‎0 - 32767‎ تولید می‌کند. نباید برای تولید یک کلید رمزنگاری به کار برود.

مثال ‎9-11‎. تولید اعداد تصادفی

#!/bin/bash

# ‎$RANDOM‎ در هر نوبت یک عدد صحیح تصادفی متفاوتی برگشت می‌دهد.
#  محدوده اسمی آن: ‎0 - 32767‎ (صحیح علامت‌دار شانزده بیتی) است.

MAXCOUNT=10
count=1

echo
echo "$MAXCOUNT random numbers:"
echo "-----------------"
while [ "$count" -le $MAXCOUNT ]      # تولید 10 ‎($MAXCOUNT)‎ عدد صحیح تصادفی.
do
  number=$RANDOM
  echo $number
  let "count += 1"  # count افزایش
done
echo "-----------------"

#  اگر به عدد صحیح تصادفی در یک محدوده معین نیاز دارید، عملگر modulo را 
#      .به کار ببرید. این عملگر، باقیمانده یک عمل تقسیم را برگشت می‌دهد

RANGE=500

echo

number=$RANDOM
let "number %= $RANGE"
#           ^^
echo "Random number less than $RANGE  ---  $number"

echo

#  اگر به یک عدد صحیح تصادفی بزرگتر از یک حداقل نیاز دارید، آنوقت یک
#+ .تست را برای صرفنظر از تمام اعداد پایین‌تر از آن حداقل، تنظیم کنید

FLOOR=200

number=0   # ارزش‌گذاری
while [ "$number" -le $FLOOR ]
do
  number=$RANDOM
done
echo "Random number greater than $FLOOR ---  $number"
echo

   #        بیایید یک جایگزین ساده را برای حلقه فوق امتحان
   #       کنیم، یعنی ‎let "number = $RANDOM + $FLOOR"‎ را که
   #     .را حذف کرده و سریع‌تر اجرا خواهد گردید ‎while‎ حلقه
   # اما شاید یک مشکل با آن وجود داشته باشد. آن مشکل چیست؟

#.ترکیب دو شیوه فوق برای تحصیل عدد تصادفی محدود بین دو عدد
number=0   # ارزش‌گذاری
while [ "$number" -le $FLOOR ]
do
  number=$RANDOM
  let "number %= $RANGE"  #  کاهش ‎$number‎ به کمتر از ‎$RANGE‎
done
echo "Random number between $FLOOR and $RANGE ---  $number"
echo

# تولید گزینه دوحالته، یعنی کمیت true یا false.
BINARY=2
T=1
number=$RANDOM

let "number %= $BINARY"
#   توجه کنید که ‎let "number >>= 14"‎ پراکندگی تصادفی بهتری ارایه می‌کند.
#+  (تمام ارقام غیر از آخرین رقم باینری را از سمت راست، بیرون می‌ریزد)
#مترجم: در اصل number مساوی آخرین بیت سمت چپ عدد تصادفی تولیدی می‌شود.
if [ "$number" -eq $T ]
then
  echo "TRUE"
else
  echo "FALSE"
fi  

echo

          #                              .ایجاد یک حرکت پرتاب تاس 
SPOTS=6   #      باقیمانده تقسیم بر ‎6‎ محدوده ‎0 - 5‎ را بیان می‌کند.
          #      با افزودن 1، محدوده مورد نظر ‎1 - 6‎ تامین می‌گردد.
          # با تشکر از Paulo Marcel Coelho Aragao، برای ساده‌سازی.
die1=0
die2=0
# بهتر نخواهد بود فقط ‎SPOTS=7‎ تنظیم شود و 1 اضافه نشود؟ چرا یا چرا نه؟

#     .پرتاب‌های جداگانه هر تاس، و بنابراین احتمال‌های درست ارایه می‌شود

    let "die1 = $RANDOM % $SPOTS +1"    # انداختن تاس اول.
    let "die2 = $RANDOM % $SPOTS +1"    # انداختن تاس دوم.
    #            کدام عملیات حسابی بالا، دارای اولویت بیشتر
    #+                 هستند، باقیمانده ‎(%)‎ یا افزایش ‎(+) ‎؟

let "throw = $die1 + $die2"
echo "Throw of the dice = $throw"
echo

exit 0

مثال ‎9-12‎. کشیدن یک کارت اتفاقی از یک دسته ورق

#!/bin/bash
# pick-card.sh

# .این یک مثال از انتخاب تصادفی عناصر یک آرایه است

# یک کارت بکشید، هر کارتی

Suites="Clubs
Diamonds
Hearts
Spades"

Denominations="2
3
4
5
6
7
8
9
10
Jack
Queen
King
Ace"

# .توجه کنید متغیرها در چند سطر پخش شده‌اند

suite=($Suites)                # .خواندن به داخل متغیر آرایه
denomination=($Denominations)

num_suites=${#suite[*]}        # .شمارش تعداد عناصر
num_denominations=${#denomination[*]}

echo -n "${denomination[$((RANDOM%num_denominations))]} of "
echo ${suite[$((RANDOM%num_suites))]}


# $bozo sh pick-cards.sh
# Jack of Clubs

# با تشکر از jipe برای نشان دادن این مورد استفاده از ‎$RANDOM‎.
exit 0

مثال ‎9-13‎. شبیه‌سازی حرکت Brownian

#!/bin/bash
# brownian.sh
#  مولف: Mendel Cooper
#  ‎تاریخ انتشار: ‎10/26/07
#  مجوز: GPL3

#  ----------------------------------------------------------------
#                  این اسکریپت حرکت Brownian را طرح‌ریزی می‌کند:
#+  حرکت تصادفی ذرات  ریز معلق در یک مایع، همچنانکه به وسیله
#+    .جریان‌ها و برخوردهای تصادفی به طور نامنظم نوسان می‌کنند
#+      این اصطلاحاً «‎Drunkard's Walk‎»(حرکت مستانه) گفته می‌شود.

#    در نظر ‎Galton Board‎ همچنین می‌تواند به عنوان یک شبیه‌سازی حداقلی از یک
#+ گرفته شود، یک صفحه شیبدار که با یک الگوی خاص گل‌میخ‌ کوبی گردیده و گروهی
#+                   .از گلوله‌هایکی یکی روی این صفحه به طرف پایین می‌غلطند
#+      در پایین یک ردیف شیار یا انبارک‌هایی وجود دارد که گلوله‌ها در پایان
#+                                   .سفرشان در آنها از حرکت باز می‌ایستند
#   .مترجم: در صورت تمایل، می‌توانید یک شبیه‌سازی نمایشی زیبا از صفحه گالتون را در اینجا  مشاهده نمایید
#       .با حداقل امکانات لازم تصور کنید ‎Pachinko‎ آن را به عنوان نوعی بازی
#         همچنانکه با اجرای اسکریپت مشاهده می‌کنید، اکثر  گلوله‌ها در اطراف 
#+                                                 .شیار مرکزی جمع می‌شوند
#+                         .این با توزیع دوجمله‌ای مورد انتظار مطابقت دارد
#      به عنوان یک شبیه‌ساز Galton Board، اسکریپت پارامترهایی از قبیل زاویه 
#+       انحراف صفحه، اصطکاک غلطشی گلوله‌ها، زاویه‌های برخورد، و خاصیت فنری
#+                                               .گل‌میخ‌ها رانادیده می‌گیرد
#                    این مورد تا چه اندازه بر دقت شبیه‌سازی تاثیر می‌گذارد؟
#  ----------------------------------------------------------------

PASSES=500            #         .تعداد ذرات شرکت کننده در واکنش (گلوله‌ها)‏
ROWS=10               #         .تعداد «برخورد» (یا سطرهای افقی دندانه‌ها)‏
RANGE=3               #                   محدوده ‎0 - 2‎ برای خروجی ‎$RANDOM‎
POS=0                 #                                  .وضعیت چپ و راست
RANDOM=$$             # .اسکریپت ‎PID‎ بنیاد کردن تولید کننده عدد تصادفی از

declare -a Slots      #             .آرایه نگهدارنده نتایج تجمیعی عبوری‌ها
NUMSLOTS=21           #                      .تعداد شیارها در انتهای صفحه


Initialize_Slots () { #                        .صفر کردن تمام عناصر آرایه
for i in $( seq $NUMSLOTS )
do
  Slots[$i]=0
done

echo                  #                          .سطر خالی در ابتدای اجرا
  }


Show_Slots () {
echo; echo
echo -n " "
for i in $( seq $NUMSLOTS )   #  .قالب‌بندی چاپ برای عناصر آرایه
do
  printf "%3d" ${Slots[$i]}   # .تخصیص سه کاراکتر برای هر نتیجه
done

echo                          # .سطر شیارها
echo " |__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|"
echo "                                ||"
echo                          #    توجه نمایید که اگر تعداد ذرات در یک شیار از ۹۹
                              #+           .تجاوز نماید، یک پیغام خطا نمایش می‌دهد
                              # اجرا با تنها ‎500‎ گلوله، معمولاً مانع این امر می‌گردد.
  }


Move () {                     #    .حرکت یک واحد به چپ -راست یا درجا ماندن
  Move=$RANDOM                # ‎$RANDOM‎ چطور تصادفی است؟ خوب، بیایید ببینیم
  let "Move %= RANGE"         #    ‎             0 - 2‎ تنظیم کردن به محدوده
  case "$Move" in
    0 ) ;;                    # کاری انجام نمی‌شود یعنی درجا می‌ماند
    1 ) ((POS--));;           #  چپ
    2 ) ((POS++));;           #  راست
    * ) echo -n "Error ";;    # .وضع نامطلوب! (هرگز نباید رخ بدهد)‏
  esac
  }


Play () {                     # .عبور واحد (حلقه داخلی)‏
i=0
while [ "$i" -lt "$ROWS" ]    # .یک مورد وقوع در هر سطر
do
  Move
  ((i++));
done

SHIFT=11                      #                   چرا ‎11‎ و نه  ‎10‎؟
let "POS += $SHIFT"           # .جابجایی «صفر موقعیت» به طرف مرکز
(( Slots[$POS]++ ))           #         برای اشکالزدایی: ‎echo $POS‎

# echo -n "$POS "

  }


Run () {                      # .حلقه خارجی
p=0
while [ "$p" -lt "$PASSES" ]
do
  Play
  (( p++ ))
  POS=0                       # تنظیم مجدد به صفر، چرا؟
done
  }

# --------------
# main ()
Initialize_Slots
Run
Show_Slots
# --------------

exit $?

#                                   :تمرین‌ها
#                               ---------------
#‎(1‎‎ نتایج را با نمودار میله‌ای عمودی، یا به صورت نمودار ‎scattergram‎‏‎ نمایش دهید.
#  ‎(2‎‎ اسکریپت را برای استفاده از ‎/dev/urandom‎ به جای کاربرد ‎$RANDOM‎ اصلاح کنید.‎‎
#                            آیا این کار، نتایج را بیشتر تصادفی خواهد نمود؟
#          ‎(3‎‎ نوعی «پویانمایی» یا خروجی گرافیکی برای حرکت هر گلوله ارایه کنید.‎

Jipe مجموعه‌ای از تکنیک‌های تولید اعداد تصادفی داخل یک محدوده را نشان می‌دهد.

#                 تولید عدد تصادفی بین ‎6‎ و ‎30‎.
   rnumber=$((RANDOM%25+6))	

#    تولید عدد تصادفی در همان محدوده ‎6 - 30‎ اما
#+                عدد باید بر  ‎3‎ بخش‌پذیر باشد.
   rnumber=$(((RANDOM%30/3+1)*3))

#   .توجه نمایید که اینمورد، همیشه کار نمی‌کند
# اگر ‎$RANDOM%30‎ صفر برگشت بدهد، ناموفق می‌شود.

#  ‎Frank Wang‎ جایگزین پایین را پیشنهاد می‌دهد:
   rnumber=$(( RANDOM%27/3*3+6 ))

Bill Gradwohl فرمول بهبودیافته‌ای که برای اعداد مثبت کار می‌کند، مطرح نموده است.

rnumber=$(((RANDOM%(max-min+divisibleBy))/divisibleBy*divisibleBy+min))

در اینجا Bill تابع فراگیرنده‌ای را عرضه می‌کند که یک عدد تصادفی بین دو کمیت تعیین شده برگشت می‌دهد.

مثال ‎9-14‎. عدد تصادفی بین کمیت‌ها

#!/bin/bash
# random-between.sh
#                               .عدد تصادفی بین دو مقدار تعیین شده 
# اسکریپت توسط Bill Gradwohl، با اندک اصلاحاتی توسط نگارنده این سند.
#            اصلاحات در سطرهای ‎183‎ و ‎185‎ توسط ‎Anthony Le Clezi‎o است.
#                                      .با مجوز استفاده گردیده است

randomBetween() {
   #   یک عدد تصادفی مثبت یا منفی بین ‎$min‎ و ‎$max‎ و قابل قسمت
   #+                             به ‎$divisibleBy‎ تولید می‌کند.
   #  .توزیع تصادفی قابل قبولی از مقادیر برگشتی ارایه می‌کند
   #
   #   Bill Gradwohl - Oct 1, 2003

   syntax() {
   # .تابع جاسازی شده در داخل تابع
      echo
      echo    "Syntax: randomBetween [min] [max] [multiple]"
      echo
      echo -n "Expects up to 3 passed parameters, "
      echo    "but all are completely optional."
      echo    "min is the minimum value"
      echo    "max is the maximum value"
      echo -n "multiple specifies that the answer must be "
      echo     "a multiple of this value."
      echo    "    i.e. answer must be evenly divisible by this number."
      echo    
      echo    "If any value is missing, defaults area supplied as: 0 32767 1"
      echo -n "Successful completion returns 0, "
      echo     "unsuccessful completion returns"
      echo    "function syntax and 1."
      echo -n "The answer is returned in the global variable "
      echo    "randomBetweenAnswer"
      echo -n "Negative values for any passed parameter are "
      echo    "handled correctly."
   }

   local min=${1:-0}
   local max=${2:-32767}
   local divisibleBy=${3:-1}
   # .مقادیر پیش‌فرض تخصیص یافته برای حالتی که پارامتر به تابع داده نشود

   local x
   local spread

   #           .اطمینان ایجاد کنیم ‎divisibleBy‎ بیایید نسبت به مثبت بودن
   [ ${divisibleBy} -lt 0 ] && divisibleBy=$((0-divisibleBy))

   #  کد کنترل سلامت
   if [ $# -gt 3 -o ${divisibleBy} -eq 0 -o  ${min} -eq ${max} ]; then 
      syntax
      return 1
   fi

   #  بررسی اینکه min و max برعکس ارایه شده‌اند
   if [ ${min} -gt ${max} ]; then
      # در آن حالت، جابجایی آنها
      x=${min}
      min=${max}
      max=${x}
   fi

   #  اگر خود min قابل قسمت به ‎$divisibleBy‎ نباشد،
   #+    آنوقت اصلاح min برای قرار گرفتن در محدوده.
   if [ $((min/divisibleBy*divisibleBy)) -ne ${min} ]; then 
      if [ ${min} -lt 0 ]; then
         min=$((min/divisibleBy*divisibleBy))
      else
         min=$((((min/divisibleBy)+1)*divisibleBy))
      fi
   fi

   #  اگر خود max قابل قسمت به ‎$divisibleBy‎ نباشد،
   #+    آنوقت اصلاح max برای قرار گرفتن در محدوده.
   if [ $((max/divisibleBy*divisibleBy)) -ne ${max} ]; then 
      if [ ${max} -lt 0 ]; then
         max=$((((max/divisibleBy)-1)*divisibleBy))
      else
         max=$((max/divisibleBy*divisibleBy))
      fi
   fi

   # ---------------------------------------------------------------------
   #                      .اکنون، انجام کار اصلی

   #           توجه کنید که جهت به دست آوردن پراکندگی صحیح نقاط
   #+         انتهایی، باید اجازه داده شود محدوده مقادیر تصادفی
   #+ بین ‎0‎ و ‎abs(max-min)+divisibleBy‎، نه ‎abs(max-min)+1‎ باشد.

   #   اندکی افزایش، توزیع مناسبی برای نقاط انتهایی فراهم می‌کند
   
   #    تغییر دادن فرمول در جهت استفاده از ‎abs(max-min)+1‎ بازهم جواب‌های
   #+  صحیح تولید می‌کند، اما آن پاسخ‌ها دارای نقص هستند، از این جهت که
   #+ تعداد دفعات برگشت داده شده برای نقاط انتهایی‏(‎$min‎ و ‎$max‎)‏ به طور
   #+        .قابل ملاحظه‌ای پایین‌تر از موقع به کار بردن فرمول صحیح است
   #  ---------------------------------------------------------------------

   spread=$((max-min))
   #  اشاره می‌کند که این تست غیر ضروری است،‏ ‎Omair Eshkenazi‎
   #+     .از قبل جابجا شده‌اند (در صورت لزوم)‏ ‎max‎ و ‎min‎ چون
   [ ${spread} -lt 0 ] && spread=$((0-spread))
   let spread+=divisibleBy
   randomBetweenAnswer=$(((RANDOM%spread)/divisibleBy*divisibleBy+min))   

   return 0

   #   اما، ‎Paulo Marcel Coelho Aragao‎ اشاره می‌کند
   #+  وقتی ‎$max‎ و ‎$min‎ قابل تقسیم به ‎$divisibleBy‎ 
   #+                  .نباشند فرمول ناموفق می‌شود
   #
   #     :او در عوض، فرمول زیر را پیشنهاد می‌نماید
   # rnumber = $(((RANDOM%(max-min+1)+min)/divisibleBy*divisibleBy))

}

#  .بیایید تابع را امتحان کنیم
min=-14
max=20
divisibleBy=3


#  ایجاد یک آرایه از پاسخ‌های مورد انتظار و کنترل برای اطمینان از اینکه اگر
#+ .به اندازه کافی طولانی تکرار کنیم حداقل یکی از هر جواب را به دست می‌آوریم

declare -a answer
minimum=${min}
maximum=${max}
   if [ $((minimum/divisibleBy*divisibleBy)) -ne ${minimum} ]; then 
      if [ ${minimum} -lt 0 ]; then
         minimum=$((minimum/divisibleBy*divisibleBy))
      else
         minimum=$((((minimum/divisibleBy)+1)*divisibleBy))
      fi
   fi


   # اگر ‎max‎ خودش قابل قسمت به ‎$divisibleBy‎ نباشد،
   #+ آنوقت اصلاح ‎max‎ برای اینکه داخل محدوده باشد‏.

   if [ $((maximum/divisibleBy*divisibleBy)) -ne ${maximum} ]; then 
      if [ ${maximum} -lt 0 ]; then
         maximum=$((((maximum/divisibleBy)-1)*divisibleBy))
      else
         maximum=$((maximum/divisibleBy*divisibleBy))
      fi
   fi


#  ما به تولید شاخص‌های فقط مثبت برای آرایه نیاز داریم، بنابراین به
#+   ‎.یک جابجا کردن که نتایج مثبت را تضمین خواهد نمود احتیاج داریم

disp=$((0-minimum))
for ((i=${minimum}; i<=${maximum}; i+=divisibleBy)); do
   answer[i+disp]=0
done


# .اکنون برای دیدن اینکه چه به دست می‌آوریم، با یک عدد بزرگ تکرار می‌کنیم
loopIt=1000   # را پیشنهاد می‌کند ‎100000‎ ،مولف اسکریپت
              #+    .اما استفاده از آن زیاد وقت می‌برد

for ((i=0; i<${loopIt}; ++i)); do

   #   توجه نمایید که ما در اینجا ‎min‎ و ‎max‎ را به ترتیب برعکس  
   #+          .مشخص نموده‌ایم تا تابع این مورد را تصحیح کند

   randomBetween ${max} ${min} ${divisibleBy}

   #      .گزارش یک خطا در صورتیکه یک پاسخ غیر منتظره باشد
   [ ${randomBetweenAnswer} -lt ${min} -o ${randomBetweenAnswer} -gt ${max} ] \
   && echo MIN or MAX error - ${randomBetweenAnswer}!
   [ $((randomBetweenAnswer%${divisibleBy})) -ne 0 ] \
   && echo DIVISIBLE BY error - ${randomBetweenAnswer}!

   # .ذخیره پاسخ در جایی دور از لحاظ آماری
   answer[randomBetweenAnswer+disp]=$((answer[randomBetweenAnswer+disp]+1))
done



#  اجازه بدهید نتایج را کنترل کنیم

for ((i=${minimum}; i<=${maximum}; i+=divisibleBy)); do
   [ ${answer[i+disp]} -eq 0 ] \
   && echo "We never got an answer of $i." \
   || echo "${i} occurred ${answer[i+disp]} times."
done


exit 0

‎$RANDOM‎ چقدر تصادفی است؟ بهترین روش برای بررسی این مطلب نوشتن اسکریپتی است که توزیع اعداد «تصادفی» تولید شده توسط ‎$RANDOM‎ را پیگیری کند. بیایید چندین بار یک تاس ‎$RANDOM‎ را بریزیم . . .

مثال ‎9-15‎. غلتاندن یک تاس منفرد با RANDOM

#!/bin/bash
#  چگونه تصادفی است؟ ‎RANDOM‎

RANDOM=$$       #    برپاسازی مجدد تولیدکننده عدد تصادفی با ‎ID‎ پردازش اسکریپت.

PIPS=6          #                                     .یک تاس دارای شش عدد است
MAXTHROWS=600   # .اگر وقت برای شما ارزش زیادی ندارد این متغیر را افزایش بدهید
throw=0         #                           .تعداد دفعاتی که تاس پرتاب شده است

ones=0          #                          شمارش‌ها باید با صفر مقداردهی بشوند،‏
twos=0          #+              .چون یک متغیر ارزش‌گذاری نشده صفر نیست، تهی است
threes=0
fours=0
fives=0
sixes=0

print_result ()
{
echo
echo "ones =   $ones"
echo "twos =   $twos"
echo "threes = $threes"
echo "fours =  $fours"
echo "fives =  $fives"
echo "sixes =  $sixes"
echo
}

update_count()
{
case "$1" in
  0) ((ones++));;   # .چون یک تاس دارای «صفر» نیست، اینمورد مطابق یک است
  1) ((twos++));;   # .و این ۲ است
  2) ((threes++));; # .و به همین ترتیب
  3) ((fours++));;
  4) ((fives++));;
  5) ((sixes++));;
esac
}

echo


while [ "$throw" -lt "$MAXTHROWS" ]
do
  let "die1 = RANDOM % $PIPS"
  update_count $die1
  let "throw += 1"
done  

print_result

exit $?

#   با فرض اینکه RANDOM تصادفی است، امتیازهای توزیع شده باید نسبتاً مساوی باشند.
#        برای ‎$MAXTHROWS=600‎ تمام گروه‌ها باید حدود ‎100‎ بعلاوه یا منهای ‎20‎ باشند.
#
#      به خاطر داشته باشید که ‎RANDOM‎ یک تولید کننده «شِبه تصادفی»
#+           .است و مورد مناسب چشمگیری برای انجام این کار نیست

#                            .تصادف، موضوع عمیق و پیچیده‌ای است
#  رشته‌های «تصادفی» به اندازه کافی طولانی ممکن است درهم و برهمی
#+          .و دیگران رفتار «غیر تصادفی» به معرض نمایش بگذارند

#                       :تمرین (آسان)‏
#                      ---------------
#  این اسکریپت را طوری بازنویسی کنید که یک سکه را هزار بار به
#  طور چرخشی به هوا پرتاب کند. انتخاب‌ها ‎"HEAD"‎ و ‎"TAIL"‎ هستند.

همان طور که در مثال اخیر دیده‌ایم، بهترین کار، دوباره بنیاد کردن تولید کننده RANDOM در هر نوبت که فراخوانی می‌شود، است. به کار بردن همان بنیاد برای RANDOM، همان گروه اعداد را تکرار می‌کند. ‎[2]‎ ( این متغیر، رفتار تابع ‎random()‎ در C را بازتاب می‌دهد.)

مثال ‎9-16‎. دوباره بنیاد کردن RANDOM

#!/bin/bash
# ‎seeding-random.sh: ‎RANDOM‎‎ بنیاد کردن متغیر
# ‎v 1.1, reldate 09 Feb 2013‎

MAXCOUNT=25       # .تعداد اعدادی که تولید می‌شوند
SEED=

random_numbers ()
{
local count=0
local number

while [ "$count" -lt "$MAXCOUNT" ]
do
  number=$RANDOM
  echo -n "$number "
  let "count++"
done  
}

echo; echo

SEED=1
RANDOM=$SEED      # تنظیم ‎RANDOM‎ تولید کننده عدد تصادفی را بنیاد می‌کند
echo "Random seed = $SEED"
random_numbers


RANDOM=$SEED      # همان بنیاد برای ‎RANDOM‎ . . .
echo; echo "Again, with same random seed ..."
echo "Random seed = $SEED"
random_numbers    # دقیقاً همان گروه اعداد را بازتولید می‌کند.
                  #
                  # دونسخه کردن یک گروه «تصادفی» چه فایده‌ای دارد؟

echo; echo

SEED=2
RANDOM=$SEED      #  تلاش دوباره، اما با یک بنیاد متفاوت . . .
echo "Random seed = $SEED"
random_numbers    #  . . . رشته اعداد متفاوتی ارایه می‌کند.

echo; echo

# ‎RANDOM=$$‎  متغیر ‎RANDOM‎ را بواسطه شماره شناسایی پردازش اسکریپت بنیاد می‌کند.
#  همچنین، بنیاد کردن ‎RANDOM‎ بر اساس فرمان‌های ‎'time'‎ یا ‎'date'‎ نیز مقدور است.

# یک مورد تفننی...
SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }'| sed s/^0*//)
#  خروجی شبه-تصادفی از ‎/dev/urandom‎  ‏(فایل-دستگاه شبه-تصادفی سیستم)‏ واکشی می‌شود
#+ سپس توسط ‎"od"‎ به سطر اعداد (اکتال) قابل چاپ تبدیل می‌شود آنوقت ‎"awk"‎ فقط یک
#+  عدد برای SEED بازیابی می‌کند، و سرانجام ‏"sed"‎ همه صفرهای مقدم را حذف می‌کند.
RANDOM=$SEED
echo "Random seed = $SEED"
random_numbers

echo; echo

exit 0

فایل شبه-دستگاه ‎/dev/urandom‎ روشی برای تولید اعداد تصادفی ساختگی بسیار «تصادفی»تر از متغیر ‎$RANDOM‎ فراهم می‌کند. سطر فرمان ‎dd if=/dev/urandom of=targetfile bs=1 count=XX‎ یک فایلِ بخوبی پخش و پلا از اعداد تصادفی ساختگی تولید می‌کند. به هرحال، در یک اسکریپت تخصیص این اعداد به یک متغیر، به راهکاری موقتی از قبیل فیلتر کردن بواسطه od (همچون در مثال فوق، مثال ‎16-14‎، و مثال ‎A-36‎)، یا حتی لوله‌کشی به md5sum (مثال ‎36-16‎ را ببینید) نیاز دارد.

روشهای دیگری نیز برای تولید اعداد تصادفی ساختگی در یک اسکریپت‌ وجود دارد. Awk یک وسیله راحت برای انجام این کار فراهم می‌کند.

مثال ‎9-17‎. اعداد تصادفی ساختگی، با استفاده از awk

#!/bin/bash
#    ‎random2.sh‎ یک عدد تصادفی ساختگی در محدوده ‎0 - 1‎ 
#+  با شش رقم اعشار برگشت می‌دهد. برای مثال: ‎0.822725‎
#     این اسکریپت تابع ‎rand()‎ از awk را به کار می‌برد.

AWKSCRIPT=' { srand(); print rand() } '
#                         فرمان(ها)-پارامترهای عبور داده شده به ‎awk‎
# توجه:  ‎srand()‎ تولید کننده عدد تصادفی awk را دوباره برپا می‌کند.


echo -n "Random number between 0 and 1 = "

echo | awk "$AWKSCRIPT"
# اگر شما ‎'echo'‎ را صرفنظر کنید چه اتفاقی رخ می‌دهد؟

exit 0


#                                   :تمرین‌ها
#                                 ------------

#  ‎(1‎ با استفاده از یک حلقه، ‎10‎ عدد تصادفی مختلف در خروجی چاپ کنید.
#  (تذکر: شما باید تابع ‎srand()‎ را در هر نوبت با یک بنیاد متفاوت به
#+ حلقه عبور بدهید. اگر این مورد را از قلم بیاندازید چه خواهد شد؟)

#       ‎(2 با استفاده از یک ضریب صحیح به عنوان عامل درجه‌بندی، اعداد‎ 
#+                         تصادفی در محدوده ‎10‎ تا ‎100‎ تولید کنید.

#     ‎(3 مانند تمرین شماره ‎2‎، اما این دفعه تولید اعداد صحیح تصادفی.‎

فرمان date نیز برای تولید رشته های عدد صحیح شبه-تصادفی مناسب است.

یادداشت‌ها

[1]

«تصادف» حقیقی در چنان درجه‌ای اگر ابدا موجود باشد، تنها می‌تواند در پدیده‌های طبیعی ناقص فهمیده شده از قبیل انهدام رادیواکتیو، یافت بشود. کامپیوترها فقط تصادف را شبیه‌سازی می‌کنند، و از این جهت رشته های اعداد «تصادفی» تولید کامپیوتر به عنوان شبه-تصادف منسوب می‌شوند.

[2]

بنیاد گروه‌های عددی شبه تصادفیِ تولیدِ کامپیوتر می‌تواند به عنوان یک برچسب هویت در نظر گرفته شود. به عنوان مثال، گروه‌های شبه-تصادفی با بنیاد ‎23‎ را به عنوان گروه‌های ‎#23‎ تصور کنید.

یک خصوصیت گروه‌های عدد شبه-تصادفی، طول چرخه قبل از شروع تکرار گروه است. یک تولید کننده شبه-تصادفی خوب، گروه‌هایی با چرخه‌های بسیار طولانی ارایه می‌کند.