shell腳本高級進階小總結
經過一周腳本的折磨,覺得還是有一定的收獲,所以就把一些不容易理解的並且容易忘記的難點做一個總結。shell腳本中主要有兩大模塊,第一就是流程控制的腳本,第二就是函數控制的腳本。
▲首先,流程控制包括順序執行,選擇執行,循環執行。主要的條件語句就是if。那就來先說說if語句吧!
1.if語句分為單分支,雙分支和多分支,並且可以嵌套。
2.多分支分為如下幾種情況
if 判斷條件1; then
條件為真的分支代碼
elif 判斷條件2; then
條件為真的分支代碼
elif 判斷條件3; then
條件為真的分支代碼
else
以上條件都為假的分支代碼
fi
逐條件進行判斷,第一次遇為“真”條件時,執行其分支,而後結束整個if語句
------------下面來舉一些多分支的示例吧
1.判斷/var/目錄下所有文件的類型
for i in /var/* ;do
if [ -b $i ];then
echo "$i塊設備文件"
elif [ -c $i ];then
echo "$i字符文件"
elif [ -d $i ];then
echo "$i目錄文件"
elif [ -f $i ];then
echo "$i普通文件"
elif [ -h $i ];then
echo "$i鏈接文件"
elif [ -p $i ];then
echo "$i管道文件"
elif [ -s $i ];then
echo "$i套接字文件"
else
echo "$i該文件不存在"
fi
done
▲其次,再來說說select選擇語句,這個語句一般可以跟case語句合並使用,case和select的語法格式如下。
1.case的語法格式,支持glob風格的通配符:
*: 任意長度任意字符
?: 任意單個字符
[]:指定範圍內的任意單個字符
a|b: a或b
case 變量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
默認分支
;;
esac
2.select主要用於創建菜單,按數字順序排列的菜單項將顯示在標準輸入上,並顯示 PS3 提示符,等待用戶輸入用戶輸入菜單列表中的某個數字,執行相應的命令用戶輸入被保存在內置變量 REPLY 中
------------舉例說明,打印菜單
PS3="please choose the menu: "
select menu in mifan hulatang jiaozi lamian huimian quit
do
case $REPLY in
1|4)
echo "the price is 20"
;;
2)
echo "the price is 12"
;;
3|5)
echo "the price is 30"
;;
6)
break
;;
*)
echo "no the option"
esac
done
▲然後說一下用的比較多的循環語句。循環語句包括for循環和while循環。
for循環語句
°格式如下:for 變量名 in 列表;do
循環體
done
°執行機制:依次將列表中的元素賦值給“變量名;每次賦值後即執行一次循環體;直到列表中的元素耗盡,循環結束。
°列表生成方式:
(1) 直接給出列表
(2) 整數列表:
(a) {start..end}
(b) $(seq [start [step]] end)
(3) 返回列表的命令
$(COMMAND)
(4) 使用glob, 如: *.sh
(5) 變量引用;
[email protected], $*
------------舉例說明,添加10個用戶user1-user10,密碼為8位隨機字符
for i in {1..10} ; do
useradd user$i
echo "user$i is created..."
password=`tr -dc ‘A-Za-z1-9‘ < /dev/urandom |head -c8`
echo $password | passwd --stdin $i &> /dev/null
done
------------舉例說明,/etc/rc.d/rc3.d目錄下分別有多個以K開頭和以S開頭的文件;分別讀取每個文件,以K開頭的輸出為文件加stop,以S開頭的輸出為文件名加start,如K34filename stop S66filename start
for i in /etc/rc.d/rc3.d/[SK]* ;do
if [ $(basename $i |cut -c1) == "k" ];then
echo `basename $i` stop
else
echo `basename $i` start
fi
done
2.while循環語句
。格式如下:while CONDITION; do
循環體
done
。CONDITION:循環控制條件;進入循環之前,先做一次判斷;每一次循環之後會再次做判斷;條件為“true”,則執行一次循環;直到條件測試狀態為“false”終止循環,所以CONDTION一般應該有循環控制變量;而此變量的值會在循環體不斷地被修正。
-----------舉例說明,編寫腳本,利用變量RANDOM生成10個隨機數字,輸出這個10數字,並顯示其中的最大值和最小值
let i=0,min=max=$RANDOM echo "$min"
while [ $i -lt 9 ];do
ran=$RANDOM
echo "$ran"
if [ $ran -le $max ];then
let max=ran
fi
if [ $ran -le $min ];then
let min=ran
fi
let i+=1
done
echo "最大值是$max,最小值是$min"
-----------舉例說明,後續六個字符串:efbaf275cd、4be9c40b8b、44b2395c46、f8c8873ce0、b902c16c8b、ad865d2f63是通過對隨機數變量RANDOM隨機執行命令:
echo $RANDOM|md5sum|cut –c1-10後的結果,請破解這些字符串對應的RANDOM值
num_array=(efbaf275cd 4be9c40b8b 44b2395c46 f8c8873ce0 b902c16c8
b ad865d2f63)
for raw_num in `seq 0 65535`;do
suijijiami=`echo $raw_num | md5sum |cut -c 1-10`
for num in ${num_array[*]};do
if [ "$suijijiami" == "$num" ];then
echo "$raw_num*****>$num_array"
fi
done
done
解析:這一題其實不難,主要就是要會反向思維,因為這些字符串都是通過隨機數加密後而成,我們都知道隨機數的一共有65536個數字,也就是說這些加密後的字符串本身沒有加密時肯定都是在0到65535之間,所以我們可以把所有的隨機數按照題目要求的方式隨機加密,然後用for語句匹配我們自己隨機加密的字符串是否跟題目上的字符串相同,如果相同,就取出相同字符串所對應的隨機數,然後就得出了結果。
▲函數的使用,函數function是由若幹條shell命令組成的語句塊,實現代碼重用和模塊化編程它與shell程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運行,而是shell程序的一部分,函數和shell程序比較相似,區別在於:Shell程序在子Shell中運行而Shell函數在當前Shell中運行。因此在當前Shell中,函數可以對shell中變量進行修改。
。函數聲明最好定義在一個單獨的文件中,不要加上shebang機制。然後調用直接調用函數source|. 函數名,因為函數本身不需要運行,只要在調用的的時候在shell腳本中運行就可以了。
。函數變量默認的是全局變量,所以要定義本地變量只影響函數內部,避免修改函數外的變量值。
。函數不能用exit退出,因為函數本身沒有開啟子進程會退出整個腳本
。函數的格式:func1 () { local name=mage;echo func1;echo $name; }
-----------舉例說明
編寫服務腳本/root/bin/testsrv.sh,完成如下要求
(1) 腳本可接受參數:start, stop, restart, status
(2) 如果參數非此四者之一,提示使用格式後報錯退出
(3) 如是start:則創建/var/lock/subsys/SCRIPT_NAME,並顯示“啟動成功”
考慮:如果事先已經啟動過一次,該如何處理?
(4) 如是stop:則刪除/var/lock/subsys/SCRIPT_NAME,並顯示“停止完成”
考慮:如果事先已然停止過了,該如何處理?
(5) 如是restart,則先stop,再start
考慮:如果本來沒有start,如何處理?
(6) 如是status, 則如果/var/lock/subsys/SCRIPT_NAME文件存在,則顯示“SCRIPT_NAMEis running...”
如果/var/lock/subsys/SCRIPT_NAME文件不存在,則顯示“SCRIPT_NAME is stopped...”
其中:SCRIPT_NAME為當前腳本名
. /etc/init.d/functions
scripts="/var/lock/subsys/`basename $0`"
start(){
if [ -e $scripts ];then
echo "服務已經啟動,不需要再次啟動"
else
touch $scripts
action "啟動成功" true
fi
}
stop(){
if [ -e $scripts ];then
rm -f $scripts
action "停止完成" true
else
echo "服務未啟動,無需停止"
fi
}
restart(){
if [ -e $scripts ];then
stop
start
else
start
fi
}
status(){
if [ -e $scripts ];then
action "`basename $0` is running......" true
else
action "`basename $0` is stopped......" true
fi
}
case $1 in
"start")
start
;;
"stop")
stop
;;
"restart")
restart
;;
"status")
status
;;
*)
echo "輸入參數有誤:`basename $0` is stop|start|restart|status"
;;
esac
解析:本題的要求就是模仿一個服務的各種狀態,當啟動的時候,存在這個服務腳本文件,則顯示已經啟動了不需要再次啟動,如果不存在這個服務腳本就創建這個服務腳本文件,並且提示啟動成功。在停止服務的時候有這個服務腳本就刪除掉這個腳本,並顯示停止成功,如果本身就沒有這個文件,就顯示服務本身就沒有啟動,無需停止。在重啟服務的時候,如果有這個腳本就先停止服務然後重啟,如果不存在這個腳本就直接重啟。狀態就是如果有這個文件就顯示服務開啟,如果沒有就顯示服務停止。
-----------舉例說明
編寫腳本/root/bin/copycmd.sh
(1) 提示用戶輸入一個可執行命令名稱
(2) 獲取此命令所依賴到的所有庫文件列表
(3) 復制命令至某目標目錄(例如/mnt/sysroot)下的對應路徑下;如:/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd
(4) 復制此命令依賴到的所有庫文件至目標目錄下的對應路徑下:如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
(5)每次復制完成一個命令後,不要退出,而是提示用戶鍵入新的要復制的命令,並重復完成上述功能;直到用戶輸入quit退出
. /etc/init.d/functions
while true;
do
read -p "請輸入一個可執行的命令(quit 退出):" command
if [ "$command" == "quit" ] ; then
exit 1
else
cmd_path=`which $command`
mkdir -p /mnt/sysroot$cmd_path
cp $cmd_path /mnt/sysroot$cmd_path && action " $cmd_path /mnt/sysroot$cmd_path " true
list=`ldd /bin/ls |grep -o "/lib.* "|tr -d " "`
[ -e /mnt/sysroot/lib64 -a -e /mnt/sysroot/lib ] || mkdir -p /mnt/sysroot/{lib64,lib}
for i in $list;do
cp $i /mnt/sysroot$i && action "$i /mnt/sysroot$i " true
done
fi
done
解析:這題看起來麻煩,其實做的時候並不是很麻煩,就是執行一個腳本,復制命令的路徑到指定的路徑下,然後把庫文件也同時復制過來。要求就是不改變原來的路徑,並且提示用戶退出的時候再退出,不提示就可以一直復制。有一個需要註意的地方就是如果多次復制一個命令的時候不要重復復制,避免出錯。
最後一題還有些地方不是很完善,希望看到的大神幫忙指正。關於腳本的就先寫到這裏了,有時間再補充。。。。。。
本文出自 “12994186” 博客,請務必保留此出處http://13004186.blog.51cto.com/12994186/1965929
shell腳本高級進階小總結