နားလည်ထားရမယ့် အချက်
filesystem ကို ထိတွေ့သော script တစ်ခုသည် file သို့မဟုတ် directory တစ်ခု မိမိမျှော်လင့်ထားသော state တွင် ရှိနေမည်ဟု တစ်ခါမျှ ယူဆသင့်ခြင်းမရှိပါ — အကြောင်းမှာ script ၏ ပတ်ဝန်းကျင်သည် script ၏ လုံးဝ ထိန်းချုပ်မှုအောက်တွင် ဘယ်တော့မှ မရှိသောကြောင့်ဖြစ်သည် — disk ပြည့်သွားနိုင်၊ path ပျောက်နေနိုင် သို့မဟုတ် နာမည်ပြောင်းထားနိုင်၊ permission မှားယွင်းနေနိုင်၊ သို့မဟုတ် script တူတူ၏ ယခင် run တစ်ခုက အခြေအနေတစ်ခုကို မမျှော်လင့်ထားဘဲ ချန်ထားခဲ့နိုင်သည်။ ထို့ကြောင့် bash က test operator မိသားစုတစ်ခုကို ပေးထားသည် — -e က တစ်ခုခု ရှိမရှိကိုသာ စစ်ဆေးပြီး၊ -f က ၎င်းကို regular file သို့ ကျဉ်းမြောင်းစေကာ၊ -d က directory ဟုတ်မဟုတ်၊ -r, -w, -x တို့ကမူ read, write, execute permission ကို အသီးသီး စစ်ဆေးပေးသည် — တစ်ခုစီသည် [[ ]] အတွင်း action မလုပ်မီ တိုက်ရိုက်သုံးနိုင်သော true သို့မဟုတ် false exit status ကို ပြန်ပေးသည်။ file state ကို စစ်ဆေးခြင်းလောက် အရေးကြီးသည့်အချက်တစ်ခုမှာ file set တစ်ခုကို ဘယ်လို enumerate လုပ်မည်ကို ဆုံးဖြတ်ခြင်းဖြစ်သည်။ *.txt ကဲ့သို့ ရိုးရိုး glob သည် ရိုးရှင်းပြီး ခန့်မှန်းနိုင်ကာ flat directory တစ်ခုအတွက် များသောအားဖြင့် လုံလောက်သော်လည်း၊ လက်ရှိ shell context နှင့် ဆက်စပ်၍သာ expand ဖြစ်ပြီး subdirectory များထဲသို့ recurse မဝင်ပါ။ find command ကမူ ပိုမိုအားကောင်းသည် — recursive search လုပ်နိုင်၊ -type ဖြင့် type အလိုက် filter လုပ်နိုင်၊ name pattern ဖြင့် filter လုပ်နိုင်ပြီး — အရေးကြီးဆုံးအချက်အနေနှင့် — null-safe read loop နှင့် ပေါင်းစပ်လိုက်လျှင် space သို့မဟုတ် ထူးဆန်းသော character ပါသော filename များကို glob တစ်ခုတည်းက တိတ်တဆိတ် မှားယွင်းနေမည့် အခြေအနေမျိုးတွင်ပင် မှန်ကန်စွာ ကိုင်တွယ်နိုင်သည်။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
target directory ထဲ ရေးမီ ၎င်းရှိမရှိ စစ်ဆေးရသော backup script တစ်ခု၊ လုပ်ငန်းစဉ်တစ်ခုအခြား process က သုံးနေနိုင်သည့် /tmp/mydata ကဲ့သို့ path ကို hardcode မလုပ်ဘဲ လုံခြုံသော scratch space ဖန်တီးခြင်း၊ တစ်ခုခု ဖျက်မီ operation တစ်ခုစီ အောင်မြင်ကြောင်း အတည်ပြုခြင်းတို့ကို စဉ်းစားကြည့်ပါ။ ဤ lesson ၏ code သည် ထိုအစဉ်လိုက်ကို အတိအကျ လိုက်နာထားသည် — work_dir=$(mktemp -d) က unique name အာမခံသော directory တစ်ခုကို ဖန်တီးပေးသဖြင့် hardcode လုပ်ထားသော temp path တစ်ခုက ဖြစ်ပေါ်စေနိုင်သော race condition သို့မဟုတ် collision မှန်သမျှကို ရှောင်ရှားပေးသည်။ work_dir ကို အသုံးချနိုင်သည်ဟု မယူဆမီ script က [[ -d "$work_dir" ]] ဖြင့် ၎င်းကို အတည်ပြုပြီး၊ -f ဖြင့် report.txt သည် (directory သို့မဟုတ် ထူးဆန်းတစ်ခုခု မဟုတ်ဘဲ) regular file အတိအကျ ဖြစ်ကြောင်း အတည်ပြုကာ၊ ၎င်းကို အားကိုးမီ -r နှင့် -w နှစ်ခုစလုံးကို တွဲစစ်ဆေးပြီး ဖတ်နိုင်၊ ရေးနိုင်စွမ်း အမှန်ရှိမရှိ ကြည့်သည် — [[ ]] တစ်ခုတည်းအတွင်း && ဖြင့် ပေါင်းစပ်ထားလျှင် condition နှစ်ခုလုံး ပြည့်မီရမည်။ negative case ကိုလည်း ပြသထားသည် — [[ ! -e "$work_dir/missing.txt" ]] က file တစ်ခုမရှိကြောင်း ယူဆရုံသက်သက်မဟုတ်ဘဲ တကယ့်တကယ် အတည်ပြုသည်။ enumeration အတွက် for file in "$work_dir"/*.txt ဟူသော glob သည် flat directory တစ်ခုအတွက် ရိုးရှင်းပြီး လုံလောက်သော်လည်း၊ find "$work_dir" -maxdepth 1 -type f -name "*.txt" | sort | while read -r file ဟူသော find version ကမူ depth၊ filtering သို့မဟုတ် ခန့်မှန်းနိုင်သော order လိုအပ်လာသည့်အခါ ရွေးချယ်သင့်သော ပို၍ ခိုင်မာသော pattern ကို ပြသသည်။ နောက်ဆုံးတွင် rm -rf ပြီးနောက် [[ $? -eq 0 ]] ကို စစ်ဆေးခြင်းသည် cleanup ပေါ်တွင် တူညီသော discipline ကို အသုံးချထားခြင်းဖြစ်သည် — destructive operation တစ်ခု run သွားသည်ဟူသောအကြောင်းတစ်ခုတည်းဖြင့် အောင်မြင်သည်ဟု ဘယ်တော့မှ မယူဆပါနှင့်။
အတူတူ စမ်းရေးကြည့်မယ်
#!/bin/bash
work_dir=$(mktemp -d)
# Create some files inside the temp directory
touch "$work_dir/report.txt"
touch "$work_dir/notes.txt"
mkdir "$work_dir/archive"
if [[ -d "$work_dir" ]]; then
echo "work_dir exists and is a directory"
fi
if [[ -f "$work_dir/report.txt" ]]; then
echo "report.txt exists and is a regular file"
fi
if [[ -r "$work_dir/report.txt" && -w "$work_dir/report.txt" ]]; then
echo "report.txt is readable and writable"
fi
if [[ ! -e "$work_dir/missing.txt" ]]; then
echo "missing.txt does not exist"
fi
echo "Looping over .txt files with a glob:"
for file in "$work_dir"/*.txt; do
echo "Found: $(basename "$file")"
done
echo "Looping over files with find:"
find "$work_dir" -maxdepth 1 -type f -name "*.txt" | sort | while read -r file; do
echo "Found via find: $(basename "$file")"
done
rm -rf "$work_dir"
if [[ $? -eq 0 ]]; then
echo "Cleanup succeeded"
fiဤ script ကို run လိုက်လျှင် အောက်ပါအတိုင်း output ရရှိမည်−
work_dir exists and is a directory
report.txt exists and is a regular file
report.txt is readable and writable
missing.txt does not exist
Looping over .txt files with a glob:
Found: notes.txt
Found: report.txt
Looping over files with find:
Found via find: notes.txt
Found via find: report.txt
Cleanup succeeded၅ မိနစ် စမ်းကြည့်
mktemp -d ဖြင့် temporary directory တစ်ခု ဖန်တီးပြီး ၎င်းသို့ ရေးသားနိုင်ခြင်းရှိမရှိ စစ်ဆေးကာ၊ extension မတူညီသော file နှစ်ခုကို ၎င်းထဲတွင် ဖန်တီးပြီး၊ extension တစ်ခုတည်းနှင့် ကိုက်ညီသော file များကိုသာ loop ဖြင့်ပတ်၍ ၎င်းတို့၏ name များကို print ထုတ်ပြီးနောက် အားလုံးကို ရှင်းလင်းသော script တစ်ခု ရေးပါ။
သတိလေးတစ်ချက်
*.txt ကဲ့သို့ glob တစ်ခုကို မည်သည့် file နှင့်မျှ ကိုက်ညီမကိုက်ညီ စစ်ဆေးခြင်းမရှိဘဲ loop ပတ်ခြင်း — file တစ်ခုမျှ မကိုက်ညီပါက bash သည် expand မဖြစ်သော literal string "*.txt" ကို loop ထဲ ထည့်ပေးလိုက်သည်
cp သို့မဟုတ် mv ကဲ့သို့ command တစ်ခု run သွားသည်ဟူသောအကြောင်းတစ်ခုတည်းဖြင့် အောင်မြင်သည်ဟု ယူဆခြင်း — original file ကို ဖျက်မီ exit status ($?) ကို စစ်ဆေးသင့်သည်
GNU Bash Manual: Bash Conditional Expressions — Bash / Shell Scripting