Thuta Learning
Bash / Shell Scripting
BasicDevOps & Toolsbeginner

Loop များ: for, while, until

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

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

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

`for` loop သည် ကြိုတင်သိရှိ (သို့) တွက်ချက်ထားနိုင်သော item list ပုံသေတစ်ခုပေါ်တွင် ထပ်ခါလုပ်ပေးသည် — ကိုယ်တိုင်ရေးထားသော word များ၊ loop မစခင်ကတည်းက shell က matching filename များအဖြစ် expand လုပ်ပြီးသား `*.log` ကဲ့သို့ glob pattern၊ (သို့) word list မဟုတ်ဘဲ numeric counter တကယ်လိုအပ်ချိန် classic C-style `for ((i=0; i<n; i++))`။ `while` loop မှာမူ condition ကို ထပ်ခါစစ်ဆေးနေပြီး true ဖြစ်နေသရွေ့ run နေမည်ဖြစ်သည် — ၎င်းကြောင့် iteration ဘယ်နှစ်ကြိမ်ရှိမည်ကို ကြိုတင်မသိသည့်အခါများတွင် သဘာဝကျသော ရွေးချယ်မှုဖြစ်သည် — `while read` ဖြင့် line တစ်ကြောင်းချင်းစီ input ဖတ်ခြင်း (သို့) state တစ်ခု ပြောင်းသည်အထိ ထပ်ခါလုပ်ခြင်းစသည်။ `until` သည် `while` ၏ ကြေးမုံပုံရိပ်ဖြစ်ပြီး true အစား condition false ဖြစ်နေသရွေ့ run သည် — readability အတွက်သာ ရှိပြီး loop တစ်ခုသည် 'X မဖြစ်သေးသရွေ့ ဆက်လုပ်' ထက် 'X ဖြစ်တဲ့အထိ ဆက်လုပ်' ဟု သဘာဝကျစွာ ဖတ်ရသည့်အခါများအတွက် ဖြစ်သည်။ ၎င်းသုံးမျိုးထဲမှ မည်သည့်အရာတွင်မဆို `break` က condition ကို ထည့်မတွက်တော့ဘဲ loop ကို ချက်ချင်း ထွက်စေပြီး၊ `continue` က iteration လက်ရှိ၏ ကျန်ရှိသေးသော body ကို ကျော်ကာ နောက်တစ်ကြိမ်သို့ တိုက်ရိုက် ခုန်ကူးစေသည်။ ကနဦးမှာသိထားသင့်သော အသေးစိတ်တစ်ခုမှာ — ၎င်းက လူတိုင်းလိုလို ပထမဆုံးအကြိမ်တွင် အမှားစားတတ်သောကြောင့်ဖြစ်သည် — pipeline တစ်ခုသည် stage တစ်ခုစီအတွက် process သီးခြားစီ fork လုပ်သောကြောင့် `while read` loop ထဲသို့ command တစ်ခုကို pipe ထည့်ခြင်း (`cmd | while read ...`) သည် loop တစ်ခုလုံးကို subshell ထဲတွင် run စေသည် — ဆိုလိုသည်မှာ counter တစ်ခုကဲ့သို့ loop က ပြောင်းလဲလိုက်သော variable မည်သည့်အရာမဆို loop ပြီးသွားသည်နှင့် loop မစခင်က တန်ဖိုးအတိုင်း ချက်ချင်း ပြန်ရောက်သွားမည်ဖြစ်ပြီး၊ ၎င်းကို lesson ၏ ဥပမာကိုယ်တိုင်က တိုက်ရိုက် ပြသထားသည်။

လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်

Log file တစ်ခုကို line တစ်ကြောင်းချင်းစီ process လုပ်ပြီး pattern နှင့် ကိုက်ညီသော line ဘယ်နှစ်ကြောင်းရှိလဲ ရေတွက်ခြင်းသည် `while read` ၏ classic use case ဖြစ်သည် — `while IFS= read -r line; do ...; done < file.txt` က line တစ်ခုစီကို (`IFS=` က ထိန်းသိမ်းပေးသော leading/trailing space များပါ) naive approach တစ်ခုတွေ့ရမည့် word-splitting အံ့သြစရာများမပါဘဲ ဘေးကင်းစွာ ဖတ်ပေးသည်၊ ၎င်းသည် lesson ၏ ဥပမာက `lines.txt` ကို ဖတ်ကာ `total` counter ကို 3 အထိ တိုးမြှင့်သည့်အချိန် တိတိကျကျ လုပ်ဆောင်သည့် အရာဖြစ်သည်။ ထို့ပြင် network call တစ်ခုကို ငါးကြိမ်အထိ retry လုပ်ရန် လိုအပ်သော script တစ်ခုမှာ C-style `for` loop ကို `break` နှင့် ပေါင်းစပ်သုံးရန် သဘာဝကျသည် — call အောင်မြင်တာနှင့် loop ကို ချက်ချင်း ရပ်လိုက်ပြီး attempt ငါးကြိမ်လုံးကို အမြဲ run နေရန် မလိုတော့ပါ။ ဥပမာ၏ နောက်ဆုံး block သည် subshell gotcha ကို အတိအကျ ပြသသည် — `printf` output ကို `while read` ထဲသို့ pipe ထည့်လိုက်ခြင်းက loop အတွင်း `count` ကို 3 အထိ တိုးပေးသော်လည်း၊ ထို loop သည် pipeline အတွက် fork ခံထားသော subshell ထဲတွင် run နေသောကြောင့် pipeline ပြီးသွားသည်နှင့် ပြင်ပရှိ `count` သည် 0 အတိုင်းသာ ကျန်ရှိနေမည်ဖြစ်သည် — ၎င်းသည် file ထဲမှ redirect (`< file.txt`) လုပ်ခြင်းက ရှောင်ရှားပေးနိုင်သော အံ့သြစရာအမျိုးအစားပင် ဖြစ်သည်။

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

bash
#!/usr/bin/env bash
echo "for over a list:"
for color in red green blue; do
  echo "  color -> $color"
done

echo "for over a glob:"
mkdir -p /tmp/bash-lesson-loops
touch /tmp/bash-lesson-loops/a.log /tmp/bash-lesson-loops/b.log
for f in /tmp/bash-lesson-loops/*.log; do
  echo "  found -> $(basename "$f")"
done

echo "C-style for:"
for ((i = 1; i <= 3; i++)); do
  echo "  i -> $i"
done

echo "while loop:"
n=3
while [ "$n" -gt 0 ]; do
  echo "  countdown -> $n"
  n=$((n - 1))
done

echo "until loop:"
m=1
until [ "$m" -gt 3 ]; do
  echo "  climbing -> $m"
  m=$((m + 1))
done

echo "break and continue:"
for num in 1 2 3 4 5; do
  if [ "$num" -eq 2 ]; then
    continue
  fi
  if [ "$num" -eq 4 ]; then
    break
  fi
  echo "  num -> $num"
done

echo "while read from a file:"
printf 'line one\nline two\nline three\n' > /tmp/bash-lesson-loops/lines.txt
total=0
while IFS= read -r line; do
  echo "  read -> $line"
  total=$((total + 1))
done < /tmp/bash-lesson-loops/lines.txt
echo "total lines counted: $total"

echo "the subshell gotcha (piped while read):"
count=0
printf 'x\ny\nz\n' | while IFS= read -r _; do
  count=$((count + 1))
done
echo "count after piped loop: $count"

rm -rf /tmp/bash-lesson-loops
You should see
ဤ script ကို run လိုက်လျှင် အောက်ပါအတိုင်း ထွက်ပါမည်:

for over a list:
  color -> red
  color -> green
  color -> blue
for over a glob:
  found -> a.log
  found -> b.log
C-style for:
  i -> 1
  i -> 2
  i -> 3
while loop:
  countdown -> 3
  countdown -> 2
  countdown -> 1
until loop:
  climbing -> 1
  climbing -> 2
  climbing -> 3
break and continue:
  num -> 1
  num -> 3
while read from a file:
  read -> line one
  read -> line two
  read -> line three
total lines counted: 3
the subshell gotcha (piped while read):
count after piped loop: 0

၅ မိနစ် စမ်းကြည့်

task1.txt, task2.txt, task3.txt ဟု အမည်ရှိ file သုံးခု ဖန်တီးသော script တစ်ခု ရေးပါ၊ for-loop glob ဖြင့် ၎င်းတို့ပေါ်တွင် loop လုပ်ပြီး filename တစ်ခုစီ print ပါ၊ ထို့နောက် counter ပါသော while loop တစ်ခုကို သီးခြားသုံးပြီး 5 မှ 1 အထိ countdown print ပါ။

သတိလေးတစ်ချက်

Command တစ်ခုကို while read ထဲသို့ pipe ထည့်ခြင်း (cmd | while read ...) ပြီးနောက် loop ထဲတွင် တိုးထားသော counter သည် ဘာကြောင့် မူလတန်ဖိုးအတိုင်း ပြန်ဖြစ်နေသလဲ မသိဖြစ်ခြင်း — pipe က loop ကို subshell ထဲတွင် run စေသောကြောင့်ဖြစ်သည်

read တွင် -r ထည့်ဖို့ မေ့ခြင်းကြောင့် input ထဲရှိ backslash များကို literal အတိုင်း မဖတ်ဘဲ interpret/strip ဖြစ်သွားခြင်း

GNU Bash Reference Manual — Looping ConstructsBash / Shell Scripting

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

  • Command တစ်ခုကို while read ထဲသို့ pipe ထည့်ခြင်း (cmd | while read ...) ပြီးနောက် loop ထဲတွင် တိုးထားသော counter သည် ဘာကြောင့် မူလတန်ဖိုးအတိုင်း ပြန်ဖြစ်နေသလဲ မသိဖြစ်ခြင်း — pipe က loop ကို subshell ထဲတွင် run စေသောကြောင့်ဖြစ်သည်
  • read တွင် -r ထည့်ဖို့ မေ့ခြင်းကြောင့် input ထဲရှိ backslash များကို literal အတိုင်း မဖတ်ဘဲ interpret/strip ဖြစ်သွားခြင်း
  • နမူနာ code ကို production system ပေါ် တိုက်ရိုက်မစမ်းဘဲ local/test environment တွင် အရင်အတည်ပြုပါ။

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

task1.txt, task2.txt, task3.txt ဟု အမည်ရှိ file သုံးခု ဖန်တီးသော script တစ်ခု ရေးပါ၊ for-loop glob ဖြင့် ၎င်းတို့ပေါ်တွင် loop လုပ်ပြီး filename တစ်ခုစီ print ပါ၊ ထို့နောက် counter ပါသော while loop တစ်ခုကို သီးခြားသုံးပြီး 5 မှ 1 အထိ countdown print ပါ။

You'll know it worked when: ဤ script ကို run လိုက်လျှင် အောက်ပါအတိုင်း ထွက်ပါမည်: for over a list: color -> red color -> green color -> blue for over a glob: found -> a.log found -> b.log C-style for: i -> 1 i -> 2 i -> 3 while loop: countdown -> 3 countdown -> 2 countdown -> 1 until loop: climbing -> 1 climbing -> 2 climbing -> 3 break and continue: num -> 1 num -> 3 while read from a file: read -> line one read -> line two read -> line three total lines counted: 3 the subshell gotcha (piped while read): count after piped loop: 0

Loop များ: for, while, until | Thuta Learning