Sunday, June 13, 2010

Clean script ( shell scripting)

Google docs ထဲၾကည့္ရင္းနဲ႕ အရင္က Shell script တိုတိုေလး တစ္ခုကို post လုပ္ျပီး ေရးဖို႕ စိတ္ကူးရလို႕။ Analysing လိုလို post ေတြက ေလွ်ာက္သာေရးေနတာ ကိုယ့္ဟာကိုယ္လည္း ပ်င္းတယ္။

ဒီ script မ်ိဳးကို က်ေနာ္တို႕က clean script လို႕ေခၚပါတယ္။ တကယ္ အလုပ္လုပ္တာက process kill တာပါ။ တခ်ိဳ႕ service ေတြက start ရင္ပဲျဖစ္ျဖစ္ stop ရင္ပဲျဖစ္ျဖစ္ တဝက္တပ်က္မွာ ရပ္သြားတာမ်ိဳးရွိတတ္ပါတယ္။ ျပန္ start ရင္လည္း service က run ေနျပီလို႕ေျပာတယ္။ Process list ထဲမွာလည္းရွိတယ္။ Log ထဲမွာက error ၾကီးနဲ႕ access လုပ္လို႕မရဘူး။ တခါတေလ service port ေတာင္ မပြင့္လိုက္ဖူး။ Stop လုပ္လို႕လည္းမရေတာ့ဘူး။ လြယ္လြယ္ေျပာရင္ေတာ့ Hang သြားတာေပါ့။ ဒါဆို kill မွရေတာ့မယ္။ ဒါမ်ိဳးက Failover Cluster လိုမ်ိဳးမွာ သုံးေလ့ရွိပါတယ္။ တစ္ဖက္မွာ hang ေနရင္ kill လိုက္၊ ျပန္စၾကည့္ ၊ ထပ္ hang ရင္ ထပ္ kill ျပီး ေနာက္ server တစ္လုံးကို failover လုပ္သြား၊ admin ကို mail ေလးဘာေလးပို႕။ ( MySQL ဆို file access permission error ရွိရင္ အဲဒါမ်ိဳးျဖစ္တက္တယ္။ )

Service kill တာပဲ ကိုယ့္ဟာကိုယ္ ps ေလး႐ိုက္ျပီးၾကည့္ ၊ pid ေလးမွတ္ျပီး kill လိုက္႐ံုေပါ့။ ဒါက manual လုပ္မွ ျဖစ္မွာပါ။ Administrator တစ္ေယာက္က ဘယ္မွာ ဘာ hang ေနလည္း သိဖို႕ စိတ္တန္ခိုးရွိမွ ျဖစ္မယ္၊ မဟုတ္ရင္ သိလိုက္မွာ မဟုတ္ဖူး။ တစ္ခါတစ္ေလ ဒီ server ေတြကို Veritas Cluster တို႕ဘာတို႕လို Server and service monitor ေတြနဲ႕ monitor လုပ္ခိုင္းထားျပီး service status ကို သူ႕ဟာသူ စစ္ခိုင္းထားတာမ်ိဳး၊ လူကိုယ္တိုင္ manual လုပ္ရတာမ်ိဳး နည္းႏိုင္သမွ် နည္းေအာင္ လုပ္ခ်င္တာမ်ိဳးဆိုရင္ေတာ့ script ေလးေတြလိုျပီ။ Veritas က ဒီ serivce hang ေနမွန္းသိရင္ (ဒါကလည္း တျခား script တစ္ခုနဲ႕ စစ္တာမ်ိဳးပါ) clean script ကိုေခၚျပီး kill လိုက္ပါတယ္။ ျပီးမွ start script ကို ေခၚျပီး ျပန္ စတာေပါ့။

#!/bin/sh

pid=`/usr/bin/ps -ef | /usr/bin/grep mysqld | grep -v grep|awk -F' ' '{print $2}'`;

if test "$pid" = "" ; then
echo "Process is not Running";
else
echo "Killing process..."
kill -9 $pid;
fi


ဒီ script မွာ mysqld ကို ဥပမာ အေနနဲ႕ေပးထားပါတယ္။ Script ေလးကိုျပန္ၾကည့္ရေအာင္။

ပထမ line မွာ #!/bin/sh လို႕ေပးထားတာက Shell Env ကို sh shell လို႕သက္မွတ္တာပါ။ ဒီ script က bash shell မွာလည္း အလုပ္လုပ္ပါတယ္။

ဒုတိယ line က ဒီ script မွာ အဓိက အလုပ္လုပ္တယ့္ line ပါ။
pid=`/usr/bin/ps -ef | /usr/bin/grep mysqld | grep -v grep | awk -F' ' '{print $2}'`;


pid ဆိုတယ့္ variable တစ္ခုယူလိုက္ပါတယ္။ ဘာ type ျဖစ္ရမယ္လို႕ ၾကိဳသတ္မွတ္ေပးဖို႕မလိုပါဘူး။ pid ထဲကို value တစ္ခုထဲ့တယ့္ေနရာမွာ နည္းနည္းအေသးစိတ္ပါတယ္။ ေနာက္က command ေတြကိုအရင္စမ္းၾကည့္၊ လိုခ်င္တယ့္ result ရမွ ဒီline ကိုေရးတာေကာင္းပါတယ္။ #ps -ef | grep mysqld နဲ႕ MySQL service ရဲ့ process id ကိုၾကည့္လို႕ရပါတယ္။ ဒါေပမယ့္ -ef ရဲ့ ထုံးစံအရ၊ MySQL ရဲ့ pid အျပင္ အခု run လိုက္တယ့္ grep command ရဲ့ pid ပါျပေနတယ္။ ဒါဆို pid အပိုတစ္ခုပါေနတယ္။ ဒါဆိုမလိုအပ္တယ့္ grep ရဲ့ pid ကို ဖယ္ထုတ္မယ္။ grep -v grep ကိုသုံးပါတယ္။ grep -v က invert match လို႕ေခၚတယ့္ option ပါ။ grep -v grep လို႕ေပးလိုက္ေတာ့ grep ရဲ့ pid က လြဲရင္ လို႕ ဆိုလိုလိုက္တာပါ။ ဒါဆို mysqld တစ္လိုင္းထဲရျပီ။ ( တကယ္လို႕ တျခားမဆိုင္တာေတြရွိရင္လည္း ဖယ္ရပါလိမ့္မယ္။ ဒါမွမဟုတ္လည္း result ထဲက ေနာက္တစ္ခုကို ထပ္ grep လိုက္ေပါ့။ ) လိုခ်င္တာ တစ္လိုင္းထဲရျပီဆိုရင္ လိုခ်င္တယ့္ Process ID တစ္ခုထဲကို pid variable ထဲကို ထဲ့ဖို႕ လိုပါတယ္။ တစ္လိုင္းလုံးေပးလိုက္လို႕မရပါဘူး။ ဒီမွာ awk ကိုသုံးျပီး pattern filtering လုပ္ပါတယ္။ awk -F' ' ဆိုတာက awk ကိုသုံးျပီး output result ကို filed ေတြခြဲလိုက္တာပါ။ ဘာနဲ႕ ခြဲလည္းဆိုေတာ့ -F ဆိုတယ့္ Field separator နဲ႕ field ေတြကို space နဲ႕ခြဲထားတယ္လို႕ ေျပာလိုက္ပါတယ္။ -F ရဲ့ ေနာက္က quote ေလးႏွစ္ခုၾကားမွာ space တစ္ခ်က္ပါပါတယ္။ ေနာက္က '{print $2}' ဆိုတာကေတာ့ ခုနက space ေတြနဲ႕ခြဲထားတယ့္ထဲက ဒုတိယ field ကိုပဲျပပါလို႕ ေျပာတာပါ။ ဒါဆို Mysqld ရဲ့ process id တစ္လုံးထဲရပါျပီ။ အဲဒီ process id number ကို pid ဆိုတယ့္ variable ထဲကို ထည့္လိုက္ပါတယ္။

ေျပာစရာ က်န္ခဲ့တာက equal sign ေလးရဲ့ေနာက္က command execution တစ္ခုလုံးကို ` ` ႏွစ္ခုၾကားမွာေရးပါတယ္။ Keyboard မွာ 1 ေဘးကေကာင္ေလးေပါ့။ exec comand နဲ႕ ခက္ဆင္ဆင္တူပါတယ္။ ဒီ line မွာ Mysqld က run ေနရင္ mysqld ရဲ့ pid ကို output result အျဖစ္ pid variable ထဲထည့္လိုက္ျပီး ၊ run မေနဖူးဆိုရင္ ဘာ output မွမထြက္တယ့္အတြက္ pid variable က empty value ပဲ ဆက္ျဖစ္ေနပါလိမ့္မယ္။

ဒုတိယ line ကရလာတာကို မွ if .. else နဲ႕ ျပန္စစ္ျပီး အလုပ္လုပ္ပါျပီ။
if test "$pid" = "" ; then

if test နဲ႕စစ္ျပီး then ရဲ့ေနာက္က (ေအာက္က) line ေတြကို အလုပ္လုပ္ပါတယ္။ if test "$pid" = "" လို႕စစ္လိုက္တယ့္အရ $pid ထဲမွာ ဘာ value မွမရွိပဲ blank ျဖစ္ေနမယ္ဆိုရင္ ေအာက္ကလိုင္းျဖစ္တယ့္ echo ကိုအလုပ္လုပ္ပါတယ္။

else နဲ႕ တကယ္လို႕ pid variable မွာ value တစ္ခုခုရွိေနမယ္ ဆိုရင္ process kill ေၾကာင္း echo msg ေလးတစ္ေၾကာင္းေပးျပီး kill -9 $pid နဲ႕ pid variable ထဲမွာပါလာတယ့္ process id number ကို kill ပါတယ္။ ဒီမွာ process က hang ေနတာမို႕ -9 နဲ႕ မွရပါလိမ့္မယ္။

ဒီမွာ နည္းနည္း ထြန္႕စရာေလးေတြ ရွိေသးတယ္။ ps မွာ -ef option ကမ်က္စိေနာက္တယ္။ -ae နဲ႕ မရဖူးလားဆို ရပါတယ္။ print မွာ $1 ျဖစ္သြားပါလိမ့္မယ္။ Unix style နဲ႕ aux နဲ႕ဆိုရင္ေတာ့ $2 ပါပဲ။ ကိုယ့္ဟာကိုယ္ျပင္ေပါ့။ -ae က MySQL လိုမ်ိဳး process name ရွင္းမွ အဆင္ေျပပါတယ္။ Java လိုေကာင္ေတြဆိုရင္ Java ဆိုတယ့္ process name နဲ႕ပဲ ေခၚထားတယ့္ class ေပၚမွာမူတည္ျပီး မတူညီတယ့္ process ေတြျဖစ္တက္ပါတယ္။ အဲဒါမ်ိဳးဆို ps -ef နဲ႕ java ကို တစ္ခါ ၊ classname ကိုတစ္ခါ grep မွ လိုခ်င္တယ့္ process ကိုအတိအက်ရပါလိမ့္မယ္။

If test မွာလည္း "" နဲ႕ blank လို႕မစစ္ပဲ NULL ျဖစ္မျဖစ္စစ္ရင္လည္း ရပါတယ္။ Space ေလးေတြျဖဳတ္ေရးရပါလိမ့္မယ္။ Knowledge sharing သက္သက္ပါ။ က်ေနာ္လည္း shell scripting expert မဟုတ္လို႕ ဒီထက္လြယ္ကူတယ့္ နည္းလမ္းလည္း ရွိႏိုင္ပါတယ္။ သိရင္ ျပန္လာ share ပါ။ စိတ္ဝင္စားပါတယ္။ :D

2 comments:

Zephyr said...

မသိဘူး .... ဒါနဲ႕ပဲ ဖတ္ျပီးျပန္သြားတယ္ ...။

ျပန္လာမရွဲလိုက္ႏိုင္ဘူး ... နာသကြာ

Divinity said...

Draft post ခုႏွစ္ခုနဲ႕ အစ္ကိုၾကီး၊ မေတြ႕တာၾကာျပီေနာ္ ဟဲဟဲ :D