Thuta Learning
Bash / Shell Scripting
BasicDevOps & Toolsbeginner

Function များနှင့် Variable Scope

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • Function များနှင့် Variable Scope concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • နမူနာ code ကို ကိုယ်တိုင် run ပြီး output စစ်နိုင်ရန်
  • Tutorial Platform project နှင့် production scenario တွင် မှန်ကန်စွာအသုံးချနိုင်ရန်

နားလည်ထားရမယ့် အချက်

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` သည် လုံးဝ မထိခိုက်ဘဲ ကျန်ရှိနေသည်။

အတူတူ စမ်းရေးကြည့်မယ်

bash
#!/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"
You should see
ဤ 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 FunctionsBash / Shell Scripting

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • Function ထဲတွင် local ချန်ထားခြင်းကြောင့် script ၏ တခြားနေရာတွင်သုံးထားသော variable အမည်တူတစ်ခု တိတ်တဆိတ် အစားထိုးခံရခြင်း (မတော်တဆ global leakage)
  • return ကို 0-255 integer exit-status များသာ လက်ခံကြောင်း၊ တခြားမည်သည့်အရာမဆို truncate ဖြစ်ခြင်း (သို့) error တက်ခြင်းကို မသိဘဲ တွက်ချက်ထားသော string (သို့) number ကို return ဖြင့် ပြန်ပေးရန် ကြိုးစားခြင်း
  • နမူနာ code ကို production system ပေါ် တိုက်ရိုက်မစမ်းဘဲ local/test environment တွင် အရင်အတည်ပြုပါ။

လေ့ကျင့်ခန်း

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 ပါ။

You'll know it worked when: ဤ 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

Function များနှင့် Variable Scope | Thuta Learning