目錄
需求:
腳本實現思路
要點:
需求:
sleep 作為daemon進程運行,可以以配置文件的方式指定睡眠時長。 以及要實現切換mode start/kill 。
腳本實現思路先使用getopt實現對參數以及選項的解析。(-- 後面解析的是非選項型參數)
對解析到的參數進行判斷是否合法?
例如配置文件是否為空?
參數是否可以一起使用?
将解析到的參數保存在變量中以便在後續的功能中使用。
給默認值,像ls,如果不寫選項,肯定會有默認選項的
sleep的默認就是start模式,start模式必須跟一個時間或者配置文件,否則應該提示用戶輸入時間。
sleep默認的pid輸出文件為/tmp/mysleep.pid
再實現腳本的具體功能、例如start、kill..
要點:有的選項是需要有默認值的
有的選項不能同時出現,例如-s 和 -k不能同時出現。sleep時長的配置指定時間或者配置文件即可。
詳細的注釋已在腳本中,歡迎大家點贊拍磚。
#!/usr/bin/bash
# author: ninesun
# date: 2022年1月4日22:27:23
VERSION=1.0
usage(){
cat <<'EOF'
Usage: $0 [options] [TIME]
options:
-s,--start start
-k,--kill kill
-p,--pidfile pidfile
-c,--config config
--help help
--version version
EOF
}
pstreeStatus(){
pstree -p | grep sleep
}
# ------------------------------------- getopt對選項和參數的處理START--------------------
# -o 解析短選項 skhvp:c:,p:c:中的冒号代表是參數型選項,其後一定要跟參數,例如 -p "123" -c "456"
# -l 解析長選項 start,kill,pidfile:,config:,help,version. 選項之間逗号隔開,冒号含義和-o選項一緻.
# -- 之後都為參數,$@ 取的當前腳本所傳進去的參數列表。作為getopt的parameter。 getopt按照 -o -l的格式進行解析。
# 解析之後的參數列表賦給parameters
parameters=`getopt -o skhvpt:c: -l start,kill,pidfile:,config:,help,version,status -- "$@"`
[ $? -ne 0 ] && exit 1 # getopt 如果解析失敗,退出腳本.
eval set -- "$parameters" # set 的--選項代表将命令行參數轉換為位置參數$1 $2.. 以便後續腳本使用方便
while true;do
case "$1" in #使用shift命令将參數 一直往左移動,使case一直處理第一個位置的參數
-p|--pidfile) pidfile=$2; shift 2;; #-p指定pidfile存放的位置. 對于選項型參數,選型和參數兩個位置,因此要shift 2
-s|--start) [ -z "$mode"] && mode="start" || exit 1; shift;; # -z 判斷mode是否為空,為空則默認為start。
-k|--kill) [ -z "$mode"] && mode="kill" || echo "-s and -k can't use together..."; exit 1; shift;; # -s和-k不能一起使用
-c|--config) config=$2; shift 2;; # sleep 時間的配置文件
-t|--status) pstreeStatus;exit ;;
-h|--help) usage;exit ;;
-v|--version) echo $VERSION;exit;;
--) #-- 代表解析到非選項型參數,即 睡眠時間。 時間可以放在任何位置.
shift # 向左移動一個位置,将--移出,是第一個參數為時間
time=$1 # ,shift之後, $1為時間參數
break # 已經解析到getopt格式化之後的最後一個參數了。因此break 直接跳出while循環.
;;
*)
usage;exit 4 #
;;
esac
done
# 如果沒有給任何選項,必須默認給一個操作模式
[ -z "$mode" ] && mode="start" # 默認是start
# pid文件,默認為/tmp/mysleep.pid
[ -z "$pidfile" ] && pidfile=/tmp/mysleep.pid
# ------------------------------------- 對sleep 時間參數的處理 START---------------------
# -s模式下config和TIME給且僅給一個,應該判斷同時存在,是否存在配置?、是否存在參數? 三種情況
#-k模式下可以不需要$time
case "$mode" in
start)
if [ -n "$config" -a -n "$time" ];then # [ -n "$config" ]config 非空(非0),返回0(true)。以-a為分隔 ,左邊和右邊進行邏輯與。 相與為真代表傳了兩個時間參數.
echo "-c(--config) and TIME can't use together..."
exit 1
elif [ -n "$config" ];then #config 如果非空,read 讀取,read
if [ -r "$config" ];then #配置文件是否可讀
read line <$config
[ -z "$line" ] && exit 1
#"${line//[0-9]/}"替換line變量中的數字為空,正常情況應該為空,如果非空代表pid包含非數字.
[ -n "${line//[0-9]/}" ] && { echo "config file must contain num...";exit 1; }
time=$line
else
echo "config unreadable"
exit 1
fi
elif [ -n "$time" ];then
[ -n "${time//[0-9]/}" ] && { echo "time must contain num...";exit 1; }
else
echo "give me a time to sleep..."
exit 1
fi
;;
kill)
;;
*)
usage;exit 1
esac
echo mode: $mode
echo time: $time
echo pidfile: $pidfile
# ------------------------------------- 實際業務主邏輯Start-------------------------------
# 啟動進程
startmysleep(){
pidfile=$1
time=$2
( sleep $time & echo $! ) >>"${pidfile}" # 小括号會在一個子shell中執行. 所以echo $!打印當前sleep執行的pid要放在小括号裡面。
}
# 殺sleep:找到pid文件,然後殺掉進程
killmysleep(){
pidfile=$1
if [ -r "${pidfile}" ];then
while read pid;do
[ -z "$pid" ] && exit 1 # 如果為pid空則退出
# -n "${pid//[0-9]/}" 檢查pid是否合法
#兩個斜杠//代表貪婪替換。替換pid張紅的數字,pid一定是隻有數字的,如果pid中含有字母或空,則替換之後肯定為空,-n 如果不為空代表pid中有非法字符則退出.
[ -n "${pid//[0-9]/}" ] && exit 1
kill $pid && rm -rf ${pidfile}
done <${pidfile}
return 0
fi
return 1
}
case "$mode" in
start)
startmysleep $pidfile $time
;;
kill)
killmysleep $pidfile
;;
*)
usage
esac
,