۳۴ – رشتهها و اعداد (Strings And Numbers)
برنامههای کامپیوتری اساساً دربارهٔ کار با داده هستند. در فصلهای گذشته، تمرکز ما روی پردازش دادهها در سطح فایل بود؛ اما بسیاری از مسائل برنامهنویسی نیازمند پردازش واحدهای کوچکتری مانند رشتهها (strings) و اعداد (numbers) هستند.
در این فصل، چندین قابلیت شِل را بررسی میکنیم که برای دستکاری رشتهها و اعداد مورد استفاده قرار میگیرند. شِل مجموعهٔ متنوعی از گسترش پارامترها (parameter expansions) دارد که عملیات رشتهای انجام میدهند.
علاوه بر گسترش عددی (Arithmetic Expansion) که در فصل ۷ به آن اشاره کردیم، برنامهٔ رایجی به نام bc نیز وجود دارد که محاسبات سطح بالا انجام میدهد.
گسترش پارامتر (Parameter Expansion)
در فصل ۷ به گسترش پارامتر اشاره کردیم، اما وارد جزئیات نشدیم زیرا بیشتر آنها در اسکریپتها استفاده میشوند، نه روی خط فرمان.
ما قبلاً با برخی از این گسترشها کار کردهایم؛ برای مثال، متغیرهای شِل.
ولی شِل امکانات بسیار بیشتری ارائه میکند.
پارامترهای ساده (Basic Parameters)
سادهترین نوع گسترش پارامتر استفادهٔ معمولی از متغیرهاست. مثلاً:
$a
که هنگام گسترش، مقدار متغیر a را تولید میکند.
یا میتوان متغیر را داخل آکولاد قرار داد:
${a}
این کار در برخی موارد لازم است؛ مثلاً زمانی که متغیر در کنار متن دیگری قرار میگیرد و ممکن است باعث سردرگمی شِل شود:
مشکل نمونه
[me@linuxbox ~]$ a="foo"
[me@linuxbox ~]$ echo "$a_file"
شِل تلاش میکند متغیر a_file را گسترش دهد، نه متغیر a.
راه حل
[me@linuxbox ~]$ echo "${a}_file"
foo_file
همچنین برای دسترسی به پارامترهای موضعی بالاتر از ۹، باید از آکولاد استفاده کرد:
${11}
گسترشها برای مدیریت متغیرهای خالی (Expansions To Manage Empty Variables)
این گسترشها برای حالتهایی مفید هستند که یک متغیر تعریف نشده یا خالی است.
اغلب برای مدیریت آرگومانهای کم یا تنظیم مقدار پیشفرض بهکار میروند.
۱. ${parameter:-word}
اگر parameter خالی یا تعریف نشده باشد → مقدار word برگردانده میشود.
اگر مقدار داشته باشد → مقدار خودش برگردانده میشود.
مثال:
foo=
echo ${foo:-"substitute value if unset"}
# خروجی: substitute value if unset
اگر foo مقدار داشته باشد:
foo=bar
echo ${foo:-"substitute value if unset"}
# خروجی: bar
۲. ${parameter:=word}
مانند مورد قبل است، اما word علاوه بر گسترش، به خود parameter نیز اختصاص داده میشود.
مثال:
foo=
echo ${foo:="default value if unset"}
# خروجی: default value if unset
echo $foo
# اکنون foo همین مقدار را دارد
توجه: پارامترهای موضعی (مثل $1 و …) را نمیتوان با این روش مقداردهی کرد.
۳. ${parameter:?word}
اگر parameter خالی باشد:
- پیام خطا چاپ میشود،
- اسکریپت با خطا خاتمه مییابد.
مثال:
foo=
echo ${foo:?"parameter is empty"}
# خروجی: bash: foo: parameter is empty
اگر مقدار داشته باشد:
foo=bar
echo ${foo:?"parameter is empty"}
# خروجی: bar
۴. ${parameter:+word}
اگر parameter خالی باشد → هیچ چیزی خروجی نمیدهد.
اگر مقدار داشته باشد → مقدار word خروجی میشود (اما مقدار parameter تغییر نمیکند).
مثال:
foo=
echo ${foo:+"substitute value if set"}
# (خروجی ندارد)
foo=bar
echo ${foo:+"substitute value if set"}
# خروجی: substitute value if set
گسترشهایی که نام متغیرها را برمیگردانند
${!prefix*}
${!prefix@}
هر دو فرم، فهرست نام متغیرهایی را که با prefix شروع میشوند برمیگردانند.
مثال:
echo ${!BASH*}
خروجی شامل همهٔ متغیرهای محیطی شروعشونده با BASH خواهد بود.
عملیات روی رشتهها (String Operations)
بخش مهمی از parameter expansion به دستکاری رشتهها اختصاص دارد.
۱. ${#parameter} – طول رشته
foo="This string is long."
echo "'$foo' is ${#foo} characters long."
خروجی:
'This string is long.' is 20 characters long.
اگر parameter برابر @ یا ***** باشد، تعداد پارامترهای موضعی برگردانده میشود.
۲. برش (Substring)
فرمها
${parameter:offset}
${parameter:offset:length}
مثالها:
foo="This string is long."
echo ${foo:5}
# خروجی: string is long.
echo ${foo:5:6}
# خروجی: string
offset منفی
echo ${foo: -5}
# خروجی: long.
echo ${foo: -5:2}
# خروجی: lo
۳. حذف قسمتهایی از ابتدای رشته
${parameter#pattern} # کوتاهترین برداشت
${parameter##pattern} # بلندترین برداشت
مثال:
foo=file.txt.zip
echo ${foo#*.}
# txt.zip
echo ${foo##*.}
# zip
۴. حذف از انتهای رشته
${parameter%pattern}
${parameter%%pattern}
مثال:
echo ${foo%.*}
# file.txt
echo ${foo%%.*}
# file
۵. جستجو و جایگزینی (Search & Replace)
${parameter/pattern/string} # فقط اولین
${parameter//pattern/string} # همهٔ موارد
${parameter/#pattern/string} # فقط اگر ابتدای رشته باشد
${parameter/%pattern/string} # فقط اگر انتهای رشته باشد
مثال:
foo=JPG.JPG
echo ${foo/JPG/jpg}
# jpg.JPG
echo ${foo//JPG/jpg}
# jpg.jpg
echo ${foo/#JPG/jpg}
# jpg.JPG
echo ${foo/%JPG/jpg}
# JPG.jpg
افزایش کارایی با جایگزینی دستورهای خارجی
مثال از فصل قبل: برنامه longest-word
بهجای:
len=$(echo $j | wc -c)
میتوان از:
len=${#j}
استفاده کرد که سریعتر و کارآمدتر است.
نسخهٔ بهینهشده:
len=${#j}
مقایسهٔ سرعت
- نسخهٔ قدیمی: ۳.۶ ثانیه
- نسخهٔ جدید: ۰.۰۶ ثانیه
بهبود بسیار قابل توجه.
تبدیل حروف بزرگ/کوچک (Case Conversion)
نسخههای جدیدتر bash از تبدیل رشتهها به حروف بزرگ یا کوچک پشتیبانی میکنند.
برای این کار، bash چهار گسترش پارامتر (parameter expansion) و دو گزینه برای دستور declare ارائه میدهد.
اما تبدیل حروف به چه درد میخورد؟
غیر از جنبهٔ ظاهری، این کار نقش مهمی در برنامهنویسی دارد.
مثلاً تصور کنید میخواهیم یک مقدار ورودی کاربر را در یک پایگاه داده جستجو کنیم. ممکن است کاربر آن مقدار را بهصورت:
- کامل با حروف بزرگ،
- کامل با حروف کوچک،
- یا ترکیبی از هر دو
وارد کند.
ما نمیخواهیم پایگاه دادهٔ خود را با هزاران حالت متفاوت از حروف بزرگ/کوچک پر کنیم.
راهحل: نرمالسازی (normalize) ورودی کاربر
یعنی قبل از انجام جستجو، تمام حروف ورودی را به یک شکل استاندارد تبدیل کنیم.
مثلاً همیشه به lowercase یا همیشه به UPPERCASE.
bash امکان انجام این کار را فراهم میکند.
تبدیل حروف با declare
با دستور declare میتوانیم تعیین کنیم که یک متغیر همیشه به صورت uppercase یا lowercase ذخیره شود:
#!/bin/bash
# ul-declare: demonstrate case conversion via declare
declare -u upper
declare -l lower
if [[ $1 ]]; then
upper="$1"
lower="$1"
echo $upper
echo $lower
fi
در این اسکریپت:
declare -u⇒ متغیر همیشه UPPERCASE میشودdeclare -l⇒ متغیر همیشه lowercase میشود
مثال اجرا:
[me@linuxbox ~]$ ul-declare aBc
ABC
abc
ورودی کاربر (“aBc”) نرمالسازی شده است.
۴ نوع گسترش پارامتری برای تبدیل حروف
Table 34-1: Case Conversion Expansions
| فرمت | نتیجه |
|---|---|
${parameter,,} |
تبدیل کل رشته به حروف کوچک |
${parameter,} |
تبدیل فقط اولین حرف به کوچک |
${parameter^^} |
تبدیل کل رشته به حروف بزرگ |
${parameter^} |
تبدیل فقط اولین حرف به بزرگ (capitalization) |
نمونه اسکریپت
#!/bin/bash
# ul-param - demonstrate case conversion via parameter expansion
if [[ $1 ]]; then
echo ${1,,}
echo ${1,}
echo ${1^^}
echo ${1^}
fi
اجرا:
[me@linuxbox ~]$ ul-param aBc
abc
aBc
ABC
ABc
در اینجا، از موقعیت پارامتری $1 استفاده شده، اما این گسترشها میتوانند روی هر رشته یا متغیری اعمال شوند.
ارزیابی و گسترش حسابی (Arithmetic Evaluation and Expansion)
در فصل ۷ با گسترش حسابی آشنا شدیم. این گسترش برای انجام عملیات ریاضی روی اعداد صحیح استفاده میشود:
$((expression))
این همان چیزی است که در دستورات شرطی arithmetic evaluation مثل:
(( expression ))
نیز استفاده میشود.
در ادامه، به فهرست کاملتری از قابلیتهای ریاضی bash میپردازیم.
مبنای اعداد (Number Bases)
در فصل ۹ دربارهٔ اعداد هشتهشتی (octal) و شانزدهشانزدهی (hexadecimal) توضیح داده شد.
در گسترشهای حسابی bash میتوان از اعداد صحیح در هر مبنایی استفاده کرد.
Table 34-2: مشخصکردن مبنای عدد
| نشانهگذاری | توضیح |
|---|---|
number |
مبنای ۱۰ (دهدهی) – حالت پیشفرض |
0number |
مبنای ۸ (octal) |
0xnumber |
مبنای ۱۶ (hexadecimal) |
base#number |
عدد در مبنای دلخواه |
مثالها:
echo $((0xff))
# 255
echo $((2#11111111))
# 255
عملگرهای یگانی (Unary Operators)
عملگرهای یگانی + و - نشانهٔ مثبت یا منفی بودن عدد هستند:
مثلاً:
-5
عملیات حسابی ساده
Table 34-3: Arithmetic Operators
| عملگر | عملیات |
|---|---|
+ |
جمع |
- |
تفریق |
* |
ضرب |
/ |
تقسیم صحیح |
** |
توان |
% |
باقیمانده (modulo) |
تقسیم صحیح در bash
bash فقط با اعداد صحیح کار میکند، بنابراین:
echo $((5 / 2))
# 2
برای همین تعیین باقیمانده اهمیت دارد:
echo $((5 % 2))
# 1
استفاده از modulo در حلقهها
باقیماندهٔ تقسیم برای ایجاد رفتارهای دورهای مفید است.
مثلاً برجستهکردن مقادیر مضرب ۵:
#!/bin/bash
# modulo : demonstrate the modulo operator
for ((i = 0; i <= 20; i = i + 1)); do
remainder=$((i % 5))
if (( remainder == 0 )); then
printf "<%d> " $i
else
printf "%d " $i
fi
done
printf "\n"
نتیجه:
<0> 1 2 3 4 <5> 6 7 8 9 <10> 11 12 13 14 <15> 16 17 18 19 <20>
انتساب (Assignment)
هرچند استفادههایش شاید در نگاه اول خیلی واضح نباشد، عبارات حسابی میتوانند عمل انتساب هم انجام دهند.
ما تا الان بارها عمل انتساب انجام دادهایم؛ هر بار که به یک متغیر مقدار میدهیم، داریم انتساب انجام میدهیم.
اما این کار را میتوانیم داخل عبارات حسابی هم انجام دهیم:
[me@linuxbox ~]$ foo=
[me@linuxbox ~]$ echo $foo
[me@linuxbox ~]$ if (( foo = 5 )); then echo "It is true."; fi
It is true.
[me@linuxbox ~]$ echo $foo
5
در مثال بالا:
- اول یک مقدار خالی به متغیر
fooمیدهیم و خالی بودنش را چک میکنیم. - بعد در دستور
ifاز عبارت حسابی(( foo = 5 ))استفاده میکنیم.
این کار دو اتفاق همزمان را رقم میزند:
- مقدار
5به متغیرfooاختصاص داده میشود. - نتیجهٔ عبارت چون عددی غیرصفر است، بهعنوان true ارزیابی میشود، پس شرط if برقرار است.
نکته مهم:
در عبارت بالا،=یعنی انتساب (assignment)، نه مقایسه.
foo = 5یعنی «fooرا برابر ۵ کن.»- اما
foo == 5یعنی «آیاfooبرابر ۵ است؟»این موضوع گیجکننده است، چون دستور
test(یا[ ]) برای مقایسهٔ رشتهای از یک=هم استفاده میکند.
یکی از دلایل ترجیح دادن[[ ]]و(( ))به جایtestهمین تفاوتهاست.
عملگرهای انتساب (Assignment Operators)
علاوه بر =, شِل چندین شکل کوتاهشدهٔ انتساب دارد:
Table 34-4: Assignment Operators
-
parameter = value
انتساب ساده؛ مقدار value به parameter داده میشود. -
parameter += value
جمع: معادل با
parameter = parameter + value -
parameter -= value
تفریق:
parameter = parameter - value -
parameter *= value
ضرب:
parameter = parameter * value -
parameter /= value
تقسیم صحیح:
parameter = parameter / value -
parameter %= value
باقیمانده:
parameter = parameter % value -
parameter++
افزایش پسوندی (post-increment):
parameter = parameter + 1(اما با رفتار خاص، توضیح پایین) -
parameter--
کاهش پسوندی (post-decrement):
parameter = parameter - 1 -
++parameter
افزایش پیشوندی (pre-increment):
parameter = parameter + 1 -
--parameter
کاهش پیشوندی (pre-decrement):
parameter = parameter - 1
اینها شورتکاتهای بسیار مفیدی برای عملیات حسابی متداول هستند.
بهخصوص ++ و -- که از زبان C گرفته شدهاند و در بسیاری از زبانها (از جمله bash) استفاده میشوند.
تفاوت ++ قبل و بعد از متغیر
این عملگرها میتوانند قبل یا بعد از نام متغیر قرار بگیرند، و هر دو مقدار متغیر را یک واحد کم/زیاد میکنند،
اما رفتارشان متفاوت است:
- اگر قبل از متغیر باشند → ابتدا متغیر تغییر میکند، بعد مقدار برگردانده میشود.
- اگر بعد از متغیر باشند → ابتدا مقدار فعلی برگردانده میشود، بعد متغیر تغییر میکند.
مثال:
[me@linuxbox ~]$ foo=1
[me@linuxbox ~]$ echo $((foo++))
1
[me@linuxbox ~]$ echo $foo
2
اینجا:
- در
foo++ابتدا مقدار فعلیfooیعنی1برگردانده میشود، - سپس مقدار
fooبه2افزایش مییابد.
اما اگر عملگر را قبل بگذاریم:
[me@linuxbox ~]$ foo=1
[me@linuxbox ~]$ echo $((++foo))
2
[me@linuxbox ~]$ echo $foo
2
اینبار:
++fooاولfooرا به ۲ افزایش میدهد،- بعد مقدار ۲ را برمیگرداند.
برای بیشتر استفادههای شِل، پیشوندی (++foo) طبیعیتر و مفیدتر است.
استفاده در حلقهها – بهبود اسکریپت modulo
عملگرهای ++ و -- معمولاً همراه حلقهها بهکار میروند.
نسخهٔ بهبودیافتهٔ اسکریپت قبلی:
#!/bin/bash
# modulo2 : demonstrate the modulo operator
for ((i = 0; i <= 20; ++i )); do
if (((i % 5) == 0 )); then
printf "<%d> " $i
else
printf "%d " $i
fi
done
printf "\n"
همان خروجی قبلی را تولید میکند، اما کد تمیزتر و خواناتر شده است.
عملیات بیتی (Bit Operations)
یک دسته از عملگرها روی اعداد در سطح بیت کار میکنند.
اینها برای کارهای سطح پایین مثل تنظیم یا خواندن فلگهای بیتی استفاده میشوند.
Table 34-5: Bit Operators
-
~
نقیض بیتی (Bitwise NOT): همهٔ بیتها را معکوس میکند. -
<<
شیفت بیتی به چپ (Left Shift): همهٔ بیتها را به سمت چپ جابهجا میکند. -
>>
شیفت بیتی به راست (Right Shift). -
&
AND بیتی: عمل AND روی تمام بیتهای دو عدد. -
|
OR بیتی: عمل OR روی تمام بیتهای دو عدد. -
^
XOR بیتی: OR انحصاری روی بیتها.
برای بیشتر اینها، نسخههای انتسابی هم وجود دارد، مثل <<= و غیره (به جز ~).
مثال: تولید توانهای ۲ با شیفت بیتی
[me@linuxbox ~]$ for ((i=0;i<8;++i)); do echo $((1<<i)); done
1
2
4
8
16
32
64
128
هر بار با 1 << i عدد ۱ را i بیت به چپ شیفت میدهیم، که معادل 2**i است.
منطق و عملگرهای مقایسه (Logic and Comparison)
در فصل ۲۷ دیدیم که دستور مرکب (( )) از عملگرهای مقایسهای مختلف پشتیبانی میکند.
اینجا لیست کاملتری از آنها را میبینیم:
Table 34-6: Comparison Operators
-
<=→ کوچکتر یا مساوی -
>=→ بزرگتر یا مساوی -
<→ کوچکتر -
>→ بزرگتر -
==→ برابر -
!=→ نابرابر -
&&→ AND منطقی -
||→ OR منطقی -
expr1 ? expr2 : expr3
عملگر سهتایی (ternary)
اگرexpr1ناصفر (true) باشد →expr2اجرا میشود،
در غیر این صورت →expr3.
در منطق حسابی:
- مقدار ۰ → false
- هر عدد غیرصفر → true
(( )) نتیجه را به کدهای خروج (exit code) شِل تبدیل میکند:
[me@linuxbox ~]$ if ((1)); then echo "true"; else echo "false"; fi
true
[me@linuxbox ~]$ if ((0)); then echo "true"; else echo "false"; fi
false
عملگر سهتایی (Ternary Operator)
این عملگر شبیه if/then/else است اما در قالب یک عبارت:
expr1 ? expr2 : expr3
مثال روی خط فرمان:
[me@linuxbox ~]$ a=0
[me@linuxbox ~]$ ((a<1?++a:--a))
[me@linuxbox ~]$ echo $a
1
[me@linuxbox ~]$ ((a<1?++a:--a))
[me@linuxbox ~]$ echo $a
0
در این مثال، یک Toggle ساختهایم:
- اگر
a < 1باشد →++aاجرا میشود - اگر نباشد →
--aاجرا میشود
و هر بار مقدار a بین ۰ و ۱ تغییر میکند.
نکته:
قرار دادن انتساب (assignment) داخل این عبارتها کمی tricky است و اگر مستقیم بنویسید، bash خطا میدهد:
[me@linuxbox ~]$ a=0
[me@linuxbox ~]$ ((a<1?a+=1:a-=1))
bash: ((: a<1?a+=1:a-=1: attempted assignment to non-variable (error token is "-=1")
راهحل: انتساب را داخل پرانتز قرار دهید:
[me@linuxbox ~]$ ((a<1?(a+=1):(a-=1)))
نمونهٔ کامل: جدول اعداد
در این اسکریپت از عملگرهای حسابی استفاده شده تا یک جدول از اعداد و مربع و مکعب آنها چاپ کند:
#!/bin/bash
# arith-loop: script to demonstrate arithmetic operators
finished=0
a=0
printf "a\ta**2\ta**3\n"
printf "=\t====\t====\n"
until ((finished)); do
b=$((a**2))
c=$((a**3))
printf "%d\t%d\t%d\n" $a $b $c
((a<10?++a:(finished=1)))
done
روند کار:
-
متغیر
finishedابتدا ۰ است → یعنی false -
حلقهٔ
untilتا وقتیfinishedصفر است ادامه مییابد. -
در هر دور:
- مربع
aدرbذخیره میشود. - مکعب
aدرcذخیره میشود. - هر سه مقدار چاپ میشوند.
- مربع
-
در انتها:
- اگر
a < 10باشد →++a - وگرنه →
finished = 1و حلقه متوقف میشود.
- اگر
خروجی:
a a**2 a**3
= ==== ====
0 0 0
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
bc – یک زبان ماشینحساب با دقت دلخواه (Arbitrary Precision Calculator Language)
دیدیم که شل میتواند همهٔ انواع محاسبات صحیح (integer) را انجام دهد؛
اما اگر بخواهیم محاسبات پیچیدهتر انجام دهیم، یا حتی فقط با اعداد اعشاری (floating point) کار کنیم چه؟
پاسخ این است که:
نمیتوانیم.
حداقل نه مستقیم با خود شل.
برای انجام چنین کارهایی باید از برنامههای خارجی استفاده کنیم.
میتوانیم از اسکریپتهای Perl یا AWK استفاده کنیم، اما اینها خارج از محدودهٔ این کتاب هستند.
راه دیگر استفاده از یک برنامهٔ مخصوص ماشینحساب است.
یکی از این برنامهها که تقریباً در همهٔ سیستمهای لینوکسی وجود دارد، bc است.
bc چیست؟
برنامهٔ bc فایلی را که به زبان مخصوص خودش (مشابه C) نوشته شده، میخواند و اجرا میکند.
یک اسکریپت bc میتواند:
- در یک فایل جداگانه باشد،
- یا از standard input خوانده شود.
bc امکانات زیادی دارد:
- متغیرها
- حلقهها
- توابع
- دقت دلخواه در محاسبات
در اینجا یک آشنایی کوتاه ارائه میشود؛ راهنمای کامل آن در man page موجود است.
یک مثال ساده
یک اسکریپت bc که ۲+۲ را حساب میکند:
/* A very simple bc script */
2 + 2
در زبان bc، کامنتها مثل C هستند:
هر چیزی بین /* و */ یک کامنت است.
اجرای bc
اگر این اسکریپت را بهصورت foo.bc ذخیره کنیم:
[me@linuxbox ~]$ bc foo.bc
...
4
نتیجه (۴) در پایین خروجی نمایش داده میشود.
برای حذف پیام خوشآمدگویی از گزینهٔ -q استفاده میکنیم.
اجرای تعاملی bc
[me@linuxbox ~]$ bc -q
2 + 2
4
quit
در حالت تعاملی، هر عبارت را تایپ میکنیم،
و پاسخ بلافاصله نمایش داده میشود.
با دستور quit از برنامه خارج میشویم.
ارسال اسکریپت از طریق استاندارد ورودی
[me@linuxbox ~]$ bc < foo.bc
4
این یعنی میتوانیم:
- here document
- here string
- pipe
برای ارسال کد به bc استفاده کنیم.
مثال here string:
[me@linuxbox ~]$ bc <<< "2+2"
4
یک اسکریپت نمونهٔ واقعی: محاسبهٔ قسط ماهانهٔ وام
در مثال زیر، یک اسکریپت bash مینویسیم که از bc استفاده میکند تا قسط یک وام را محاسبه کند:
#!/bin/bash
# loan-calc : script to calculate monthly loan payments
PROGNAME=$(basename $0)
usage () {
cat <<- EOF
Usage: $PROGNAME PRINCIPAL INTEREST MONTHS
Where:
PRINCIPAL is the amount of the loan.
INTEREST is the APR as a number (7% = 0.07).
MONTHS is the length of the loan's term.
EOF
}
if (($# != 3)); then
usage
exit 1
fi
principal=$1
interest=$2
months=$3
bc <<- EOF
scale = 10
i = $interest / 12
p = $principal
n = $months
a = p * ((i * ((1 + i) ^ n)) / (((1 + i) ^ n) - 1))
print a, "\n"
EOF
اجرا:
[me@linuxbox ~]$ loan-calc 135000 0.0775 180
1270.7222490000
اسکریپت بالا میزان قسط ماهانهٔ یک وام ۱۳۵٬۰۰۰ دلاری با نرخ بهرهٔ ۷.۷۵٪ و مدت ۱۸۰ ماه (۱۵ سال) را محاسبه میکند.
نکته مهم: scale
در bc، مقدار متغیر داخلی scale تعداد رقمهای اعشار محاسبات را تعیین میکند.
مثلاً:
scale = 10
یعنی ۱۰ رقم اعشار.
جمعبندی
در این فصل، با بسیاری از ابزارهای کوچک اما مهمی آشنا شدیم که برای انجام «کار واقعی» در اسکریپتها استفاده میشوند.
هرچه تجربهٔ ما در اسکریپتنویسی بیشتر شود، توانایی دستکاری مؤثر رشتهها و اعداد اهمیت بیشتری پیدا میکند.
اسکریپت loan-calc نمونهای نشان میدهد که چگونه حتی یک اسکریپت کوتاه میتواند کارهای بسیار مفیدی انجام دهد.
تمرین اضافی (Extra Credit)
اسکریپت loan-calc هنوز کامل نیست.
برای بهبود آن، میتوانید:
- بررسی کامل ورودیهای خط فرمان را اضافه کنید
- گزینهای برای حالت تعاملی ایجاد کنید که از کاربر مقدار وام، نرخ بهره و مدت را بپرسد
- خروجی را به شکل خواناتر و زیباتر نمایش دهید
مطالعهٔ بیشتر (Further Reading)
● مقالهٔ Bash Hackers Wiki دربارهٔ parameter expansion:
http://wiki.bash-hackers.org/syntax/pe
● Bash Reference Manual:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion
● مقالهٔ ویکیپدیا دربارهٔ bit operations:
http://en.wikipedia.org/wiki/Bit_operation
● مقالهٔ ویکیپدیا دربارهٔ ternary operations:
http://en.wikipedia.org/wiki/Ternary_operation
● فرمول محاسبهٔ وام که در اسکریپت loan-calc استفاده شده:
http://en.wikipedia.org/wiki/Amortization_calculator