နားလည်ထားရမယ့် အချက်
Bash function တစ်ခုကို `name() { ... }` ဖြင့် သတ်မှတ်ပြီး၊ သတ်မှတ်ပြီးလျှင် ၎င်းကို 'ခေါ်ခြင်း' အတွက် special syntax မလိုဘဲ အမည်ဖြင့် တခြား command တစ်ခုကဲ့သို့ ခေါ်သုံးနိုင်သည်။ Function တစ်ခုသို့ ပေးပို့သော argument များကို script argument များနှင့် အတိအကျ mechanism တူညီစွာ ရရှိနိုင်သည် — `$1`, `$2`, `$@`, `$#` — ၎င်းတို့သည် function call အသီးသီးအတွက်သာ scope ကျယ်ဝန်းသည်၊ ဆိုလိုသည်မှာ positional parameter များနှင့် `"$@"` ကို quote လုပ်ခြင်းအကြောင်း သင်ယူခဲ့ပြီးသမျှသည် syntax အသစ်တစ်ခုမျှ သင်စရာမလိုဘဲ function များတွင်လည်း တိုက်ရိုက် အသုံးချနိုင်သည်။ Default အနေနဲ့ bash တွင် variable တိုင်းသည် function ထဲ ဘယ်လောက်ပင် နက်နက်နဲနဲ assign ထားစေကာမူ global ဖြစ်နေသည် — ဒါကြောင့် function ထဲတွင် assign လုပ်လိုက်သော variable သည် `local` ဖြင့် အတိအလင်း ကြေညာမှသာလွှဲ၍ ပြင်ပရှိ အမည်တူ variable ကို တိတ်တဆိတ် အစားထိုးသွားမည်ဖြစ်သည်၊ `local` ကို ကြေညာလိုက်လျှင် ၎င်း variable ကို လက်ရှိ function call အတွက်သာ scope ကျယ်ဝန်းစေပြီး function မ run ခင်က ရှိနေခဲ့သော value (သို့) value မရှိခြင်း) ကို ပြန်လည် ရရှိစေသည်။ Bash function များသည် ဘာသာစကားအများစုက function များလို တွက်ချက်ထားသော value ကို 'return' မလုပ်ပါ — `return` သည် caller ဆီ အောင်မြင်/မအောင်မြင် အချက်ပြရန်အတွက်သာ (ပုံမှန်အားဖြင့် `if function_name; then` ဖြင့် စစ်ဆေးလေ့ရှိသည်) 0 မှ 255 အထိ numeric exit status ကိုသာ သတ်မှတ်ပေးသည်၊ data အတွက်မဟုတ်ပါ — string တစ်ခု (သို့) ထို range ပြင်ပရှိ number တစ်ခုကို return ဖြင့် ပြန်ပေးရန် ကြိုးစားခြင်းသည် fail ဖြစ်စေခြင်း (သို့) တိတ်တဆိတ် truncate ဖြစ်စေခြင်း ဖြစ်စေသည်။ Function မှ တွက်ချက်ထားသော value တစ်ခု အမှန်တကယ်ရယူရန် idiomatic pattern မှာ ရလဒ်ကို `echo` လုပ်ပြီး command substitution (`result=$(my_function)`) ဖြင့် ဖမ်းယူခြင်း၊ (သို့) အဆင်မပြေလျှင် global variable တစ်ခုကို တမင် assign လုပ်ခြင်းဖြစ်သည်။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Input စစ်ဆေးခြင်း၊ message format လုပ်ခြင်း၊ event log ချခြင်းကဲ့သို့ ထပ်ခါလုပ်ရသော အဆင့်များစွာပါဝင်သော script တစ်ခုသည် နေရာတိုင်းတွင် line များ copy-paste လုပ်နေမည့်အစား တစ်ခုစီကို function သေးသေးလေးများအဖြစ် ခွဲထုတ်ထားခြင်းက အကျိုးရှိသည် — lesson ၏ ဥပမာက greeting logic ကို `greet()` ထဲသို့၊ ပေါင်းစည်း logic ကို `sum_args()` ထဲသို့ ထည့်သွင်းထားသည့်နည်းတူပင်။ `sum_args` ကို အနီးကပ် ကြည့်ပါ — accumulate မလုပ်ခင် `local total=0` ဟု ကြေညာထားသောကြောင့် ၎င်းကို ထပ်ခါ ခေါ်သုံးလျှင်ပင် ယခင် call တစ်ခု၏ total အဟောင်း ကျန်ရှိနေခြင်း (leak) လုံးဝ မဖြစ်ပါ၊ ၎င်း၏ တကယ့်အဖြေကိုလည်း `$total` ကို `echo` ထုတ်ပြီး caller ဘက်က `result=$(sum_args 2 4 6)` ဖြင့် ဖမ်းယူစေခြင်းဖြင့် ပြန်ပေးသည် — `is_even` သုံးသော 0/1 exit status အတွက်ကြေးထားသော `return` မှတစ်ဆင့် မဟုတ်ပါ။ ဥပမာ၏ နောက်ဆုံး section သည် `local` မပါဘဲ ဘာဖြစ်တတ်သည်ကို အတိအကျ ပြသသည် — `no_local_demo` သည် `counter=1` ကို local အဖြစ် မကြေညာဘဲ assign လိုက်သောကြောင့် ပြင်ပရှိ `counter=100` ကို တိတ်တဆိတ် အစားထိုးသွားပြီး၊ function ပြန်ရောက်ပြီးနောက်တွင်ပင် `1` အဖြစ် အစားထိုးခံရဆဲ ကျန်ရှိနေသည်၊ ဒီတော့ `with_local_demo` ကမူ `local counter=999` ဟု ကြေညာထားသောကြောင့် function ပြန်ရောက်သွားသည်နှင့် အတွင်းမှာ ဘာပဲဖြစ်ဖြစ် ပြင်ပရှိ `counter` သည် လုံးဝ မထိခိုက်ဘဲ ကျန်ရှိနေသည်။
အတူတူ စမ်းရေးကြည့်မယ်
#!/usr/bin/env bash
greet() {
local name="$1"
echo "Hello, $name!"
}
greet "Maung Maung"
sum_args() {
local total=0
for n in "$@"; do
total=$((total + n))
done
echo "$total"
}
result=$(sum_args 2 4 6)
echo "Sum: $result"
is_even() {
local n="$1"
if [ $((n % 2)) -eq 0 ]; then
return 0
else
return 1
fi
}
if is_even 8; then
echo "8 is even (exit status was 0)"
fi
counter=100
no_local_demo() {
counter=1 # missing "local" - overwrites the outer/global counter!
echo "inside no_local_demo, counter = $counter"
}
with_local_demo() {
local counter=999 # local - only affects this function
echo "inside with_local_demo, counter = $counter"
}
no_local_demo
echo "after no_local_demo, global counter = $counter"
with_local_demo
echo "after with_local_demo, global counter = $counter"ဤ script ကို run လိုက်လျှင် အောက်ပါအတိုင်း ထွက်ပါမည်:
Hello, Maung Maung!
Sum: 12
8 is even (exit status was 0)
inside no_local_demo, counter = 1
after no_local_demo, global counter = 1
inside with_local_demo, counter = 999
after with_local_demo, global counter = 1၅ မိနစ် စမ်းကြည့်
String argument တစ်ခုယူပြီး uppercase version ကို echo ထုတ်ပေးသော `to_upper` function တစ်ခု ရေးပါ (function ထဲတွင် argument ကို `tr 'a-z' 'A-Z'` မှတစ်ဆင့် pipe လုပ်နိုင်သည်)၊ ၎င်း၏ ရလဒ်ကို command substitution ဖြင့် variable ထဲသို့ ဖမ်းယူပါ၊ function က global variable ကို မတော်တဆ ပြောင်းမသွားကြောင်း အတည်ပြုရန် global variable တစ်ခုနှင့်အတူ ရလဒ်ကို print ပါ။
သတိလေးတစ်ချက်
Function ထဲတွင် local ချန်ထားခြင်းကြောင့် script ၏ တခြားနေရာတွင်သုံးထားသော variable အမည်တူတစ်ခု တိတ်တဆိတ် အစားထိုးခံရခြင်း (မတော်တဆ global leakage)
return ကို 0-255 integer exit-status များသာ လက်ခံကြောင်း၊ တခြားမည်သည့်အရာမဆို truncate ဖြစ်ခြင်း (သို့) error တက်ခြင်းကို မသိဘဲ တွက်ချက်ထားသော string (သို့) number ကို return ဖြင့် ပြန်ပေးရန် ကြိုးစားခြင်း
GNU Bash Reference Manual — Shell Functions — Bash / Shell Scripting