နားလည်ထားရမယ့် အချက်
Bash တွင် string manipulation အတွက် toolkit တစ်ခုလုံးနီးပါးကို parameter expansion syntax — ${var...} ပုံစံများ — အတွင်းသို့ တိုက်ရိုက် ထည့်သွင်းထားပြီး၊ sed သို့မဟုတ် awk ကို ခေါ်ရမည့် text transformation အများစုကို shell ကိုယ်တိုင်အတွင်းမှာပင် inline လုပ်နိုင်သည်။ ${#str} က string ၏ length ကို ပေးပြီး၊ ${str:offset:length} က substring ကို ဖြတ်ထုတ်ပေးကာ၊ ${str/pattern/replacement} နှင့် ${str//pattern/replacement} တို့က pattern ၏ ပထမ occurrence သို့မဟုတ် occurrence အားလုံးကို အစားထိုးပေးပြီး၊ ${var^^} နှင့် ${var,,} တို့က uppercase သို့မဟုတ် lowercase သို့ ပြောင်းလဲပေးသည်။ trim family — ${var#pattern}, ${var##pattern}, ${var%pattern}, ${var%%pattern} — ကို အထူးဂရုစိုက်ရသည် — ဤအရာသည် axis နှစ်ခု အမှန်တကယ် ဖြစ်နေသောကြောင့်ဖြစ်သည်: # က ရှေ့ဘက်မှ trim လုပ်ပြီး % က နောက်ဘက်မှ trim လုပ်ကာ၊ double form (## သို့မဟုတ် %%) သည် greedy ဖြစ်ပြီး ဖြစ်နိုင်သမျှ အများဆုံး match ဖြစ်စေပြီး single form ကမူ ဖြစ်နိုင်သမျှ အနည်းဆုံးသာ match ဖြစ်စေသည်။ ဤအချက်ကြောင့်ပင် /usr/local/bin/script.sh ကဲ့သို့ slash များစွာပါသော path တစ်ခုတွင် ${path#*/} (ပထမ slash အထိသာ ဖြတ်ထုတ်) နှင့် ${path##*/} (နောက်ဆုံး slash အထိ ဖြတ်ထုတ်ပြီး filename ကိုသာ ကျန်ရစ်စေ) တို့သည် ရလဒ်ကွာခြားနေခြင်းဖြစ်သည်။ ဆက်စပ်သော်လည်း မတူညီသော form တစ်ခုဖြစ်သည့် ${var:-default} နှင့် ${var:?message} တို့မှာ string manipulation နှင့် မဆိုင်ပါ — variable တစ်ခု unset ဖြစ်ကောင်းဖြစ်နိုင်သည့် အခြေအနေကို လုံခြုံစွာ ကိုင်တွယ်ရန်ဖြစ်ပြီး၊ script တစ်ခုကို default value သို့ fallback ခွင့်ပြုနိုင်သလို empty string ဖြင့် တိတ်တဆိတ် ဆက်လက် run နေမည့်အစား error message ရှင်းရှင်းလင်းလင်းဖြင့် ကျယ်ကျယ်လောင်လောင် fail ဖြစ်စေနိုင်သည်။ ဤ operation များသည် separate process တစ်ခုမျှ spawn မလုပ်သောကြောင့် loop အတွင်းမှ external tool ကို ခေါ်ခြင်းထက် သိသိသာသာ ပိုမြန်ဆန်သည်။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Upload လုပ်လိုက်သော filename များကို process လုပ်ရသော script တစ်ခု ရေးနေသည်ဟု ဆိုကြပါစို့ — file extension ကို ဖြတ်ထုတ်ရန်၊ လိုအပ်သော environment variable ကို ဆက်မလုပ်ခင် သတ်မှတ်ပြီးမပြီး စစ်ဆေးရန်၊ username ကို နှိုင်းယှဉ်ခင် lowercase အဖြစ် normalize လုပ်ရန် လိုအပ်သည် — ဤ lesson ၏ code သည် ဤလို operation များကို အတိအကျ ဖော်ပြထားသည်။ archive.tar.gz မှ .tar.gz extension ကို ဖြတ်ထုတ်ခြင်းက # vs ## / % vs %% ကွာခြားချက်ကို ခိုင်လုံစွာ ပြသသည် — ${filename%.*} သည် နောက်ဆုံးမှ shortest match ကိုသာ ဖယ်ရှားပေးသဖြင့် archive.tar ကျန်ရစ်စေပြီး (.gz ပျောက်သွားသော်လည်း .tar ကျန်နေသည်)၊ ${filename%%.*} ကမူ ပထမ dot မှစ၍ အားလုံးကို greedy စွာ ဖယ်ရှားပေးသဖြင့် archive ကိုသာ ကျန်ရစ်စေသည် — extension တစ်ခုတည်းသာ ရှိသော file ဖြစ်သလား၊ .tar.gz ကဲ့သို့ compound extension ဖြစ်သလားပေါ် မူတည်၍ မည်သည်ကို လိုအပ်သည်ဆိုတာ ကွာခြားသည်။ ဤ logic အတိုင်းပင် ဆန့်ကျင်ဘက် direction ဖြင့် code ထဲရှိ path တွင်လည်း အသုံးချသည် — ${path#*/} သည် ပထမ slash အထိသာ ဖြတ်ထုတ်ပေးပြီး ${path##*/} ကမူ နောက်ဆုံး slash အထိ ဖြတ်ထုတ်ပေးသဖြင့်၊ basename ကို ခေါ်စရာမလိုဘဲ path အပြည့်အစုံမှ bare filename ကို ရယူရန် idiomatic နည်းလမ်းဖြစ်သည်။ လိုအပ်သော variable ကို validate လုပ်ရန်အတွက် ${required_var:?message} သည် ${greeting:-Hi there} ထက် တမင် ပို၍ aggressive ဖြစ်သည် — fallback value ကို တိတ်တဆိတ် အစားထိုးမည့်အစား variable unset ဖြစ်နေလျှင် သို့မဟုတ် empty ဖြစ်နေလျှင် error message ဖြင့် abort ဖြစ်စေသည်; ၎င်းသည် caller က သတ်မှတ်ပေးထားရမည့် variable တစ်ခုနှင့် destructive တစ်ခုခု မလုပ်ဆောင်မီ script ၏ အစတွင် ရှိသင့်သော behavior အတိအကျပင် ဖြစ်သည်။
အတူတူ စမ်းရေးကြည့်မယ်
#!/bin/bash
str="Hello, Bash World"
echo "Length: ${#str}"
echo "Substring: ${str:7:4}"
echo "Replace first: ${str/Bash/Shell}"
echo "Replace all: ${str//o/0}"
filename="archive.tar.gz"
echo "Remove shortest suffix: ${filename%.*}"
echo "Remove longest suffix: ${filename%%.*}"
path="/usr/local/bin/script.sh"
echo "Remove shortest prefix: ${path#*/}"
echo "Remove longest prefix: ${path##*/}"
unset greeting
echo "Default value: ${greeting:-Hi there}"
# ${var:?message} exits with an error if the variable is unset or empty
unset required_var
if (: "${required_var:?required_var must be set}") 2>/dev/null; then
echo "required_var is set"
else
echo "Caught missing variable error"
fi
name="bash"
echo "Uppercase: ${name^^}"
echo "Lowercase: ${name,,}"ဤ script ကို run လိုက်လျှင် အောက်ပါအတိုင်း output ရရှိမည်−
Length: 17
Substring: Bash
Replace first: Hello, Shell World
Replace all: Hell0, Bash W0rld
Remove shortest suffix: archive.tar
Remove longest suffix: archive
Remove shortest prefix: usr/local/bin/script.sh
Remove longest prefix: script.sh
Default value: Hi there
Caught missing variable error
Uppercase: BASH
Lowercase: bash၅ မိနစ် စမ်းကြည့်
/home/user/photos/vacation.jpg ကဲ့သို့ file path အပြည့်အစုံ ပါဝင်သော variable တစ်ခုပေးထားလျှင်၊ parameter expansion သာသုံး၍ (external command မသုံးဘဲ) directory မပါသော filename ကိုသာ print ထုတ်ပြီး၊ filename မပါသော extension ကိုသာ သီးခြား print ထုတ်ပါ။
သတိလေးတစ်ချက်
# (front မှ shortest match) နှင့် ## (front မှ longest match) ကို ရောထွေးခြင်း — slash များစွာပါသော path တစ်ခုတွင် ${path#*/} နှင့် ${path##*/} က ရလဒ်များစွာကွာခြားသည်
${var/pattern/replacement} သည် ပထမတွေ့သော occurrence တစ်ခုကိုသာ အစားထိုးကြောင်း မေ့လျော့ခြင်း — occurrence အားလုံးကို အစားထိုးရန် // ကိုသုံးရမည်
GNU Bash Manual: Shell Parameter Expansion — Bash / Shell Scripting