آموزش‌های خط فرمانی

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

آموزش‌های خط فرمانی

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

پرسش و پاسخ شماره ۲۶



از چه طریق می‌توانم ترتیب سطرهای فایلی را تصادفی نمایم(بُر زدن)؟(یا یک سطر اتفاقی از فایل را انتخاب کنم، یا انتخاب یک فایل به طور تصادفی از یک شاخه.)

یک راهکار برای تصادفی نمودن سطرها در یک فایل چنین است. این روش، تولید یک عدد تصادفی است که پیشوند هر سطر می‌شود ، سپس سطرهای حاصل، مرتب می‌گردند و اعداد حذف می‌شوند.

    #bash
    randomize() {
        while IFS='' read -r l ; do printf '%d\t%s\n' "$RANDOM" "$l"; done |
        sort -n |
        cut -f2-
    }

RANDOM توسط BASH و KornShell پشتیبانی می‌شود، اما در posix تعریف نگردیده است.

این روش نیز همان ایده است(چاپ اعداد تصادفی در ابتدای سطر، و مرتب نمودن سطرها نسبت به آن ستون) با استفاده از برنامه‌های دیگر:

    # Bourne
    awk '
        BEGIN { srand() }
        { print rand() "\t" $0 }
    ' |
    sort -n |    # مرتب نمودن عددی نسبت به اولین ستون(عدد تصادفی)‏
    cut -f2-     # حذف ستون مرتب‌سازی

این روش(احتمالاً ) سریعتر از راه حل قبلی است، اما در نگارشهای خیلی قدیمی AWK کار نمی‌کند("nawk" یا "gawk"، یا اگر موجود است ‎ /usr/xpg4/bin/awk‎ را امتحان کنید). (توجه نمایید که awk زمان epoch(مترجم: تعداد ثانیه‌های سپری شده از نیمه شب اول ژانویه سال ۱۹۷۰ که برای یونیکس به عنوان مبداء زمان تلقی می‌شود) را برای تابع ‎ srand()‎ استفاده می‌کند، که شاید برای شما به اندازه کافی تصادفی نباشد)

نگارش تعمیم یافته این پرسش می‌تواند, چگونه می‌توانم عناصر یک آرایه را بُر بزنم(درهم و برهم نمایم)؟ باشد. اگر نخواهیم از رویکرد تا اندازه‌ای بدترکیبِ مرتب‌سازی سطرها استفاده کنیم، در واقع این کار پیچیده‌تر از آنست که به نظر می‌رسد. یک روش خام نتایج جهت‌دار بدشکل به ما ارائه خواهد نمود. الگوریتم پیچیده‌تر(و صحیح) مشابه این مورد می‌باشد:

    # استفاده از متغیر آرایه سراسری. بایدتوپُر باشد(نه آرایه پراکنده)‏
    # Bash syntax.
    shuffle() {
       local i tmp size max rand

       #  جهت دار است $RANDOM به علت محدودیت دامنه $RANDOM % (i+1)
       # .با استفاده از دامنه‌ای که ضریبی از تعداد عناصر آرایه است اصلاح می‌شود
       size=${#array[*]}
       max=$(( 32768 / size * size ))

       for ((i=size-1; i>0; i--)); do
          while (( (rand=$RANDOM) >= max )); do :; done
          rand=$(( rand % (i+1) ))
          tmp=${array[i]} array[i]=${array[rand]} array[rand]=$tmp
       done
    }

این تابع عناصر یک آرایه را با استفاده از الگوریتم بُر زنی Knuth-Fisher-Yates در جا بُر می‌زند.

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

   # Bash
   n=$(wc -l < "$file")        # شمارش تعداد سطرها
   r=$((RANDOM % n + 1))       # عدد تصادفی از یک تا n
   sed -n "$r{p;q;}" "$file"   # r چاپ سطر شماره 

   #posix with awk
   awk -v n="$(wc -l<"$file")" 'BEGIN{srand();l=int((rand()*n)+1)} NR==l{print;exit}' "$file"

( برای اطلاعات بیشتر در مورد چاپ سطر شماره n این پرسش و پاسخ را ببینید.)

مثال بعد تمامی فایل را به داخل حافظه جذب می‌کند. این رویکرد زمان بازکردن مجدد فایل را صرفه‌جویی می‌کند، اما به وضوح، حافظه بیشتری مصرف می‌کند. (احتمالاً: در سیستم‌هایی با حافظه کافی و نهانگاه دیسک مؤثر، با روشهای قبلی تمام فایل را به حافظه خوانده‌اید، مگر اینکه حافظه کافی برای انجام آن موجود نباشد،که در چنین حالتی نمی‌توانید، که می‌باید ثابت می‌شد.)

   # Bash
   unset lines i
   while IFS= read -r 'lines[i++]'; do :; done < "$file"   # See FAQ 5
   n=${#lines[@]}
   r=$((RANDOM % n))   # see below
   echo "${lines[r]}"

توجه نمایید که ما در این مثال 1 را به عدد تصادفی اضافه نمی‌کنیم، زیرا آرایه سطرها از صفر شماره گذاری می‌شود.

همچنین، بعضی اشخاص می‌خواهند یک فایل اتفاقی از یک دایرکتوری را انتخاب کنند(برای امضاء یک e-mail، یا انتخاب یک فایل صوتی اتفاقی برای اجرا، یا یک تصویر تصادفی برای نمایش، و غیره). تکنیک مشابهی که می‌تواند به کار برود:

    # Bash
    files=(*.ogg)                  # Or *.gif, or *
    n=${#files[@]}                 # برای زیبایی گرایی
    xmms -- "${files[RANDOM % n]}" # انتخاب یک عضو تصادفی

توجه کنید که این چند نمونه اخیر از یک ضریب ساده متغیر RANDOM استفاده می‌کنند، بنابر این، نتایج جهت‌دار است. اگر این مشکلی برای برنامه شما می‌باشد، از تکنیک‌های ضد جهت مثال Knuth-Fisher-Yates فوق استفاده کنید.

دیگر برنامه‌های غیرقابل حمل:

  • shuf در Coreutils گنو(در نسخه‌های اخیر coreutils)

  • ‎ sort -R ‎گنو

در خصوص coreutils گنو، از نگارش 6.9 برنامه sort گنو دارای یک گزینه ‎ -R‎ (مستعار ‎ --random-sort‎)می‌باشد. به طور شگفت‌انگیز، فقط بامناطق عمومی کار می‌کند:

     LC_ALL=C sort -R file     # خروج سطرها به طور تصادفی 
     LC_ALL=POSIX sort -R file # خروج سطرها به طور تصادفی
     LC_ALL=en_US sort -R file # صرفنظر می‌کند -R به طور مؤثر از گزینه 

برای جزئیات بیشتر، ‎info coreutils sort‎ یا یک راهنمای معادل را ببینید.

  • > http://lists.gnu.org/archive/html/bug-bash/2010-01/msg00042.html به یک دام شگفت‌آور مرتبط با استفاده از RANDOM بدون مقدم نمودن $ در زمینه‌های محاسباتی معین، اشاره می‌کند. (خلاصه: تقریباً در هر وضعیتی باید‎ n=$((...math...)); ((array[n]++))‎ را بر ‎((array[...math...]++))‎ ترجیح بدهید.)

رفتار تشریح شده، در نگارشهای جاری mksh، ksh93، Bash، و Zsh به طور معکوس ظاهر می‌شود. بازهم موردی برای به خاطر سپردن به واسطه ماترک. -ormaaj


CategoryShell

پرسش و پاسخ 26 (آخرین ویرایش ‎ 2012-11-27 14:25:08 ‎ توسط geirha)


پرسش و پاسخ شماره ۲۵



چطور می‌توانم پارامترهای موضعی(مکانی) بعد از ‎ $9‎ را دستیابی کنم

به جای ‎$10‎ از ‎${10}‎ استفاده کنید. این روش در BASH و KornShell کار می‌کند، اما در پیاده‌سازی‌های قدیمی BourneShell کار نمی‌کند. یک روش دیگر برای دستیابی به پارامترهای مکانی بعد از ‎ $9‎ استفاده از for است، به عنوان مثال, برای به دست آوردن آخرین پارامتر:

    # Bourne
    for last
    do
        : # هیچ
    done

    echo "last argument is: $last"

برای به دست آوردن یک شناسه با عدد، می‌توانیم از شمارشگر استفاده کنیم:

    # Bourne
    n=12        # این شماره شناسه‌ای می‌باشد که مورد نظر است
    i=1
    for arg
    do
        if test $i -eq $n
        then
            argn=$arg
            break
        fi
        i=`expr $i + 1`
    done
    echo "argument number $n is: $argn"

مزیت این روش ازبین نرفتن شناسه‌ها است. اگر مشکلی نیست، فرمان shift پارامترهای مکانی قبلی را دور می‌اندازد:

    shift 11
    echo "the 12th argument is: $1"

به علاوه، bash و ksh93 با مجموعه پارامترهای مکانی به عنوان یک آرایه رفتار می‌کنند،و شما می‌توانید از ترکیب دستوری بسط پارامتر برای آدرس دادن به عناصر آن از راههای مختلف استفاده کنید :

    # Bash, ksh93
    for x in "${@:(-2)}"    # روی دو پارامتر آخر تکرار می‌کند‎
    for y in "${@:2}"       # روی تمام پارامترها تکرار می‌شود  ‎ $2‎ با شروع از ‎
           # استفاده کنیم مفید باشد shift که شاید برای موقعی که نمی‌خواهیم از

اگرچه دستیابی مستقیم به هر پارامتر مکانی به این روش امکان‌پذیر است، به ندرت لازم می‌شود. جایگزین رایج آن استفاده از getopts برای پردازش گزینه‌ها(به عنوان مثال، ‎ "-l"‎ یا ‎"-o filename"‎)، و سپس به کار بردن حلقه for یا while برای پردازش تمام شناسه‌ها یکی پس از دیگری است. یک توضیح از چگونگی پردازش شناسه‌های خط فرمان در پرسش و پاسخ شماره 35 در دسترس می‌باشد، و یک توضیح دیگر در http://www.shelldorado.com/goodcoding/cmdargs.html یافت می‌شود.


CategoryShell

پرسش و پاسخ 25 (آخرین ویرایش ‎ 2009-12-30 18:09:05 ‎ توسط MatthiasPopp)


پرسش و پاسخ شماره ۲۴



من متغیرهایی را در یک حلقه مقرر می‌کنم. چرا آنها پس از اتمام حلقه، ناگهان ناپدید می‌گردند؟ یا، چرا نمی‌توانم داده‌ها را برای خواندن لوله‌کشی نمایم؟

در اکثر پوسته‌ها، هر یک از فرمانهای یک لوله در پوسته فرعی جداگانه‌ای اجرا می‌گردد. نه در پوسته کاری:

    # فعال شده کار می‌کند lastpipe نگارش 4.2 با bash یا ksh88/ksh93 فقط در ‎
    # در سایر پوسته‌ها صفر را چاپ می‌کند
    linecnt=0
    printf '%s\n' foo bar | while read -r line
    do
        linecnt=$((linecnt+1))
    done
    echo "total number of lines: $linecnt"

دلیل این رفتار تعجب‌آور پنهانی، آنطور که در بالا وصف شد، آنست که هر پوسته فرعی یک محیط و زمینه متغیر جدیدی برقرار می‌کند. حلقه while فوق در پوسته فرعی جدیدی با نسخه خودش از متغیر linecnt اجرا می‌شود، که از پوسته والدش که آنرا با مقدار اولیه '0' ایجاد نموده اخذ کرده است. سپس این نسخه برای شمارش به کار می‌رود . وقتی حلقه while خاتمه می‌یابد، نسخه پوسته فرعی دور انداخته می‌شود، و مقدار اصلی متغیر linecnt پوسته والد(که مقدارش تغییر نکرده) در فرمان echo به کار می‌رود.

پوسته‌های متفاوت در این وضعیت رفتار متفاوتی نشان می‌دهند:

  • پوسته Bourne موقعی که ورودی یا خروجی هر چه(حلقه‌ها، case و غیره) به غیر از یک فرمان ساده , با استفاده از عملگر تغییر مسیر(< و >) یا لوله، تغییر مسیر داده می‌شود، یک پوسته فرعی ایجاد می‌کند.

  • BASH فقط اگر حلقه قسمتی از لوله باشد، یک پردازش جدید ایجاد می‌کند.

  • پوسته Korn فقط اگر حلقه قسمتی از یک لوله باشد، اما آخرین بخش آن نباشد پوسته فرعی ایجاد می‌کند. مثال read در بالا به طور واقعی در ksh88 و ksh93 کار می‌کند! (اما در mksh خیر)

  • POSIX رفتار bash را تصریح می‌کند، اما به عنوان یک توسعه اجازه می‌دهد هر قسمت یا تمام لوله بدون پوسته فرعی اجرا شود(به این ترتیب رفتار شل Korn را به خوبی مجاز می‌کند).

موارد بیشتر معیوب :

    # Bash 4
    # بدون حلقه نیز مشکل رخ می‌دهد
    printf '%s\n' foo bar | mapfile -t line  
    printf 'total number of lines: %s\n' "${#line[@]}" #  صفر را چاپ می‌کند 

    f() {
        if [[ -t 0 ]]; then
            echo "$1"
        else
            read -r var
        fi
    };

    f 'hello' | f
    echo "$var" # هیچ چاپ نمی‌کند

دوباره، در هر دو حالت لوله باعث می‌شود read یا بعضی فرمانها مشمول اجرا در پوسته فرعی شوند، بنابراین اثر آن هرگز در پردازش والد مشاهده نمی‌شود.

  • باید تأکید بشود که موضوع مختص حلقه‌ها نیست. خصوصیت عمومی تمام لوله‌ها می‌باشد، گرچه حلقه ‎ "while/read"‎ می‌تواند مثال استانداردی ملاحظه شود که وقتی افراد توضیحات صفحات man یا help دستور داخلی read را می‌خوانند و توجه داده می‌شوند که این دستور داده را از stdin می‌پذیرد، بارها و بارها ظاهر می‌گردد. آنها ممکن است به یاد بیاورند که داده تغییر مسیر یافته به درون دستور مرکب در سرتاسر آن دستور در دسترس است، اما درک نمی‌کنند چراتمام جایگزینی پردازشها و تغییر مسیرهای ظریفی که در سرتاسر محل‌هایی مانند FAQ #1 به کار می‌اندازند، ضروری هستند. طبعاً آنها به قرار دادن مواردی به طور مستقیم در لوله‌ها اقدام می‌کنند و ازعواقب آن سردرگم می‌شوند.

Workaroundها(راه های عبور )

  • اگر ورودی فایل است، یک تغییر مسیر ساده کفایت می‌کند:
        # POSIX
        while read -r line; do linecnt=$(($linecnt+1)); done < file
        echo $linecnt

    متأسفانه، این مورد در پوسته Bourne کار نمی‌کند، ‎sh(1) ‎ موروثی پوسته Bourne را برای راه عبور از آن ملاحظه کنید.

  • استفاده از گروه‌بندی دستورات و انجام همه چیز در پوسته فرعی:

        # POSIX
        linecnt=0
        cat /etc/passwd | {
        while read -r line ; do
            linecnt=$((linecnt+1))
        done
        echo "total number of lines: $linecnt"
        }
    این در واقع وضعیت پوسته فرعی را تغییر نمی‌دهد، اما اگر در مابقی کُد شما، چیزی از پوسته فرعی مورد نیاز نیست، آنوقت انهدام محیط موقت محلی پس از تمام شدن کار شما با آن، دقیقاً می‌تواند موردی باشد که به هر حال شما لازم دارید.
  • استفاده از جایگزینی پردازش(فقط Bash):

        # Bash
        while read -r line; do
            ((linecnt++))
        done < <(grep PATH /etc/profile)
        echo "total number of lines: $linecnt"
    این مورد در اصل مشابه workaround اول در بالا می‌باشد. ما بازهم فایلی را تغییر مسیر می‌دهیم، فقط در اینجا فایل یک لوله با نام (fifo) موقت است که توسط جایگزینی پردازش ما برای انتقال خروجی grep ایجاد گردیده است.
  • استفاده از لوله با نام:

        # POSIX
        mkfifo mypipe
        grep PATH /etc/profile > mypipe &
        while read -r line;do
            linecnt=$(($linecnt+1))
        done < mypipe
        echo "total number of lines: $linecnt"
  • استفاده از کمک پردازش(ksh و حتی pdksh و bash نسخه ۴ و oksh و mksh..):

        # ksh
        grep PATH /etc/profile |&
        while read -r -p line; do
            linecnt=$((linecnt+1))
        done
        echo "total number of lines: $linecnt"
  • استفاده از HereString(فقط Bash):

         read -ra words <<< 'hi ho hum'
         printf 'total number of words: %d' "${#words[@]}"

    عملگر ‎ <<<‎ مختص bash (نگارش 2.05b و بعد) می‌باشد، به هرحال یک روش بسیار پاکیزه و سودمند برای تعیین یک رشته کوچک لفظی برای ورودی فرمان است.

  • با شل POSIX، یا برای داده بلندتر چندسطری، می‌توانید به جای آن از here document استفاده کنید:
        # Bash
        declare -i linecnt
        while read -r; do
            ((linecnt++))
        done <<EOF
        hi
        ho
        hum
        EOF
        printf 'total number of lines: %d' "$linecnt"
  • استفاده از lastpipe (در Bash نگارش 4.2)
         # Bash 4.2
         set +m
         shopt -s lastpipe
    
         printf '%s\n' hi{,,,,,} | while read -r "lines[x++]"; do :; done
         printf 'total number of lines: %d' "${#lines[@]}"
    Bash نگارش 4.2 رفتار فوق‌الذکرِ kshمانند در Bash را معرفی نموده. یک هُشدار آن است که کنترل job نباید فعال باشد، که به این وسیله سودمندی آن در یک پوسته محاوره‌ای محدود می‌گردد.

برای مثالهای بیشتری در ارتباط با چگونگی خواندن ورودی و خُرد کردن آن به کلمات، پرسش و پاسخ شماره 1 را ببینید.


CategoryShell

پرسش و پاسخ 24 (آخرین ویرایش ‎ 2012-03-05 03:38:07 ‎ توسط ormaaj)


پرسش و پاسخ شماره ۲۳



من می‌خواهم به پوسته محاوره‌ای که مستعارها و توابع ویژه‌ای دارد، نه آنها که در ‎ ~/.bashrc‎ کاربر هست، متصل شوم.

فقط یک فایل شروع اولیه(start-up) متفاوت تعیین کنید:

bash --rcfile /my/custom/bashrc

نوع دیگر پرسش: من اسکریپتی دارم که یک محیط را تنظیم می‌کند، و من می‌خواهم در انتهای آن، کنترل را به کاربر بدهم.

در انتهای اسکریپت دستور ‎ exec bash‎ را برای آغاز کردن پوسته محاوره‌ای قرار بدهید. این پوسته از محیط ارث می‌برد(که شامل مستعارها نیست، اما اشکالی ندارد، زیرا مستعارها بسیار بد می‌باشند). البته، همچنین باید مطمئن شوید که اسکریپت شما در یک ترمینال اجرا می‌شود -- در غیر اینصورت، باید به عنوان مثال با استفاده از دستور ‎ exec xterm -e bash‎ آنرا ایجاد کنید.


CategoryShell

پرسش و پاسخ 23 (آخرین ویرایش ‎ 2010-08-20 12:27:03 ‎ توسط rrcs-24-39-102-30)


پرسش و پاسخ شماره ۲۲



چگونه می‌توانم به جای فقط اعداد صحیح، اعداد با ممیز شناور را در محاسبه استفاده کنم؟

حسابگر داخلی BASH فقط از اعداد صحیح استفاده می‌کند:

$ echo $((10/3))
3

برای اکثر عملیات درگیر با اعداد دارای ممیزشناور، باید از یک برنامه خارجی استفاده شود، به عنوان نمونه از bc، AWK یا dc:

$ echo "scale=3; 10/3" | bc
3.333

فرمان ‎ "scale=3"‎ به برنامه bc اعلام می‌کند که سه رقم دقت بعد از نقطه اعشاری لازم است.

همان مثال با dc( ماشین حساب شسته رفته و سبُک‌تر از bc):

$ echo "3 k 10 3 / p" | dc
3.333

k دقت اعشار را به 3 رقم تنظیم می‌کند، و p بالاترین قسمت پُشته را با یک کاراکتر سطر جدید چاپ می‌کند. به هر حال، پُشته جایگزین نمی‌شود.

اگر می‌خواهید اعداد اعشاری را مقایسه کنید(کوچکتر از، یا بزرگتر از) ، و bc گنو را دارید، می‌توانید چنین کنید:

# Bash
if (( $(bc <<< "1.4 < 2.5") )); then
  echo "1.4 is less than 2.5."
fi

اما،‎ x < y‎ توسط تمام نگارشهای bc پشتیبانی نمی‌شود:

# خیر HP-UX 10.20 این با برخی نگارشها کار می‌کند اما با
imadev:~$ bc <<< '1 < 2'
syntax error on line 1,

اگر می‌خواهید قابل حمل باشید، به مورد ماهرانه‌تری نیاز دارید:

# POSIX
case $(echo "1.4 - 2.5" | bc) in
  -*) echo "1.4 is less than 2.5";;
esac

این مثال 2.5 را از 1.4 تفریق می‌کند، و علامت نتیجه را کنترل می‌کند.اگر منفی باشد، عدد اول کوچکتر از دومی است. در حقیقت، ما با خروجی bc به عنوان عدد رفتار نمی‌کنیم، با آن به صورت یک رشته رفتار می‌کنیم، و فقط به اولین کاراکتر آن نگاه می‌کنیم.

میراث نگارش (Bourne):

# Bourne
case "`echo "1.4 - 2.5" | bc`" in
  -*) echo "1.4 is less than 2.5";;
esac

AWK نیز می‌تواند برای محاسبات به کار برود:

$ awk 'BEGIN {printf "%.3f\n", 10 / 3}'
3.333

در اینجا تفاوت ظریف اما مهمی بین راه حل bc و awk وجود دارد: bc فرمانها و عبارات را از ورودی استاندارد می‌خواند. از طرف دیگر awk عبارت را به عنوان بخشی از برنامه برآورد می‌کند. عبارتها در ورودی استاندارد سنجیده نمی‌شوند، یعنی فرمان ‎echo 10/3 | awk '{print $0}'‎ به جای ارزیابی، نتیجه عبارت ‎ 10/3‎ را چاپ می‌کند.

نگارشهای جدیدتر پوسته zsh و پوسته Korn یک حساب ممیز شناور داخلی، همراه با توابعی مانند‎ sin()‎ یا‎ cos()‎ در خود دارند. بنابراین بسیاری از این محاسبات، در ksh می‌توانند به طور بومی انجام شوند:

# ksh93
$ echo $((3.00000000000/7))
0.428571428571428571

مقایسه برابری دو عدد با ممیز شناور ، در واقع کار نابخردانه‌ای می‌باشد، دو محاسبه‌ای که روی کاغذ نتیجه یکسانی ارائه خواهند داد ممکن است در نتایج عددی ممیز شناور تفاوت بسیار جزئی ناشی از گِرد کردن و کوتاه‌سازی نشان بدهد. اگر می‌خواهید تعیین کنید که آیا دو عدد با ممیز شناور یکسان هستند، می‌توانید:

  • یا هر دو عدد را با دقت یکسان گِرد کنید، و بعد نتایج گِرد شده را برای برابری مقایسه کنید، یا
  • یک عدد را از دیگری تفریق نموده و مقدار خالص تفاضل را با مقدار ناچیزی به انتخاب خود مقایسه نمایید.

یکی از موارد بسیار اندکی که Bash به طور واقعی می‌تواند با اعداد ممیز شناور انجام بدهد، گرد نمودن آنها با استفاده از printf است:

# Bash 3.1
# به یکدیگر نزدیک باشند b و a ببینید اگر
# گرد کردن آنها تا دو رقم اعشار و مقایسه نتایج به عنوان رشته‌ را
a=3.002 b=2.998
printf -v a1 %.2f $a
printf -v b1 %.2f $b
if [[ $a1 = "$b1" ]]; then echo "a and b are the same, roughly"; fi

پیش‌بینی احتیاطی: بسیاری از مشکلاتی که به محاسبات ممیز شناور شباهت دارند در حقیقت می‌توانند فقط با اعداد صحیح حل بشوند، و بنابراین به این ابزارها نیازی نمی‌باشد-- به عنوان مثال، مشکلات مربوط به اعداد کسری. برای نمونه، جهت کنترل اینکه آیا نسبت دو عدد x و y، برابر با نسبت ‎   4:3 ‎ یا ‎ 16:9‎ می‌باشد، می‌توانید از موردی مشابه این سطرها استفاده کنید:

# Bash
# Variables x and y are integers
if (( $x*9-$y*16==0 )) ; then
   echo "16:9."
elif (( $x*3-$y*4==0 )) ; then
   echo "4:3."
else
   echo "Neither 16:9 nor 4:3."
fi

در یک بررسی استادانه‌تر، بدون استفاده از محاسبات ممیز شناور، می‌توانست تشخیص داده شود نزدیکترین نسبت 4:3 است یا 16:9. توجه نمایید که این مثال بسیار ساده‌ای می‌باشد و ظاهراً اعداد ممیز شناور و تقسیم را در گیر می‌سازد، که با اعداد صحیح و بدون تقسیم حل می‌شود. اگر امکان داشته باشد، به طور معمول تبدیل مشکل شما به محاسبات صحیح، ثمربخش‌تر از به کار بردن محاسبات ممیز شناور است.


CategoryShell

پرسش و پاسخ 22 (آخرین ویرایش ‎ed 2012-11-26 10:07:41 ‎ توسط geirha)