您好,登錄后才能下訂單哦!
本文是上課筆記總結,涉及細節(jié)知識點會在以后文章說明!
bash腳本編程:
腳本程序:解釋器解釋執(zhí)行;
shell: 交互式接口;編程環(huán)境;
shell: 能夠提供一些內(nèi)部命令,并且能通過PATH環(huán)境變量找到外部命令;把命令提交給內(nèi)核啟動為進程;
編程環(huán)境:
流程控制語句:
順序執(zhí)行;
循環(huán)執(zhí)行;
選擇執(zhí)行;
條件測試:真、假
$?
命令的狀態(tài)結果:
0: 真
1-255: 假
過程式的編程語言的元素:變量、流程、函數(shù)、數(shù)組
變量:局部變量、本地變量、環(huán)境變量、位置參數(shù)變量、特殊變量
變量:
數(shù)值型:整型、浮點型、布爾型
字符型:字符串
bash變量是弱類型;默認字符型;
變量引用:${VAR_NAME}
引號:
弱引用:""
強引用:''
命令引用:``
聲明某變量為整型變量:
let VAR_NAME=VALUE declare -i VAR_NAME=VALUE
聲明某變量為環(huán)境變量:
export VAR_NAME=VALUE declare -x VAR_NAME=VALUE
腳本的編寫格式:
第一行:寫明解釋器; #!/bin/bash
注釋行:所有以#開頭的行均為注釋行;會被解釋器忽略;
執(zhí)行腳本:
賦予執(zhí)行權限;指明路徑執(zhí)行;
直接傳遞腳本給bash解釋器
bash的選項:
-n: 測試腳本中是否有語法 錯誤;
-x: 調(diào)試執(zhí)行;
算術運算:
$[EXPRESSION] let VAR_NAME=EXPRESSION $((EXPRESSION)) $(expr argu1 argu2 argu3)
流程控制之一:for循環(huán)
將一段代碼反復執(zhí)行;
表達式:
for VAR in LIST; do STATEMENT1 ... done
for VAR in LIST; do statement1; statement2; ...; done
for ((初始化循環(huán)控制變量;循環(huán)條件;修正表達式)); do 循環(huán)體 done
進入條件; 退出條件;
循環(huán)體;STATEMENT1
睡眠:sleep [n]
循環(huán)次數(shù):為列表中的元素的個數(shù);
LIST:列表,包含至少一個元素的字符串集合;
(1) 直接給出;
(2) 數(shù)值列表:
(a) {start..end}
例如:{1..10}
(b) seq [start [step]] end
seq LAST seq FIRST LAST seq FIRST STEP LAST
(3) 返回列表的命令;
(4) globbing;
(5) 變量引用;
$*, $@
例如:添加3個用戶,user1, user2, user3; 密碼同用戶名;
#vi useradd.sh #!/bin/bash for username in user1 user2 user3; do useradd $username echo $username |passwd --stdin $username done
例如:添加9個用戶,user101...user109;密碼同用戶名;
#vi useradd2.sh #!/bin/bash for i in {1..9}; do useradd user10$i echo user10$i |passwd --stdin user10$i done
練習:于/tmp/test目錄中創(chuàng)建10個空文件f1,.., f10;
#vi addfile.sh #!/bin/bash directory=/tmp/test-$(date '+%Y%m%h') mkdir $directory for i in {1..10} ; do touch $directory/f$i done
練習:寫一個腳本,
(1) 創(chuàng)建"/tmp/test-當前時間"目錄;
(2) 添加10用戶tuser1,.., tuser10;
(3) 在"/tmp/test-當前時間"目錄中,創(chuàng)建10空文件f1,...,f10;
(4) 修改f1的屬主為tuser1;依次類推;
#vi creatdir.sh #!/bin/bash dir=/tmp/test-$(date '+%F-%H-%S') mkdir $dir for i in {1..10} ; do useradd testuser$i touch $dir/f$i chown testuser$i $dir/f$i done rm -rf $dir userdel testuser$i
練習:求100以內(nèi)所有正整數(shù)之和;
#vi plus.sh #!/bin/bash sum=0 for i in `seq 100`;do sum=$(($sum+$i)) done echo $sum
練習:求100以內(nèi)所有偶數(shù)之和;以及所有奇數(shù)之和;
#!/bin/bash declare -i sum=0 for i in `seq 1 2 100`;do sum=$(($sum+$i)) done echo $sum declare -i sum1=0 for i in `seq 2 2 100`; do sum1=$(($sum1+$i)) done echo $sum1 練習5:計算當前系統(tǒng)上所有用戶ID之和; #!/bin/bash sum=0 for i in `cut -d: -f3 /etc/passwd` ; do sum=$(($sum+$i)) done echo $sum
練習:傳遞參數(shù)(文本文件路徑)給腳本,統(tǒng)計所有文件的空白行數(shù)之和;顯示此次共對多少文件進行統(tǒng)計;
#!/bin/bash sum=0 num=0 echo $# for i in `seq 1 $# `; do num=`grep '^$' $1 |wc -l` sum=$(($num+$sum)) shift done echo $sum
練習:顯示當前系統(tǒng)所有默認shell為bash的用戶的總數(shù);并統(tǒng)計此些用戶ID之和;
for id in `grep "/bin/bash$" /etc/passwd | cut -d: -f3`; do
#!/bin/bash sum=0 num=0 for i in `grep 'bash$' /etc/passwd |cut -d: -f3` ; do sum=$(($sum+$i)) num=$(($num+1)) done
for的幾種特殊情況:
(1) for省略,會自動獲取腳本參數(shù)列表;
(2) C編程風格:
for ((變量賦值;循環(huán)條件;修正表達式)); do
CMD1
CMD2
done
(3) 循環(huán)嵌套:
for i in [LIST1]; do
CMD1
for j in [LIST2]; do
CMD2
...
done
done
練習:寫一個腳本
(1) ping 172.16.X.Y內(nèi)的所有主機;
172.16.0-255.1-254
for i in {0..255}; do for j in {1..254}; do ping -c1 -w1 172.16.$i.$j done done
練習:寫個腳本
(1) 傳遞一些目錄給腳本;
(2) 逐個顯示每個目錄下的所有一級文件的內(nèi)容類型;
(3) 統(tǒng)計一個有多少個目錄;一共顯示了多少個文件;
#!/bin/bash # declare -i dirs=0 declare -i files=0 for d in $*; do for f in $d/*; do file $f let files++ done let dirs++ done echo "Directories: $dirs." echo "Files: $files."
bash命令退出和退出狀態(tài)碼
命令在bash中執(zhí)行結束退出時,其執(zhí)行成功與否可通過退出狀態(tài)碼來記錄
#echo $?
腳本的退出狀態(tài)碼取決于執(zhí)行的最后一條命令;自定義退出狀態(tài)碼:
exit #
成功:0
失?。?-255
#!/bin/bash ls /varr retval=$? echo 'hello' exit $retvel
以ls /varr的結果狀態(tài)為退出狀態(tài)
注意:提前退出腳本,也可使用exit命令實現(xiàn)
bash 腳本編程之條件測試:
if/then結構
條件測試:
test EXPRESSION [ EXPRESSION ] [[ EXPRESSION ]]
COMMAND:使用的是命令退出狀態(tài)碼
1.使用命令執(zhí)行結果
a.使用命令引用
b.使用比較操作符
例如:
[ `id -u $username ` -lt 500 ] userid=`id -u $username` [ $userid -lt 500]
2.使用命令的退出狀態(tài)碼
a.先運行命令
b.引用狀態(tài)碼
引用方式兩種:
1.if COMMAND &>/dev/null;then
引用的是命令運行的退出狀態(tài)碼
注意:COMMAND不能被使用命令引用,COMMAND的執(zhí)行結果通常沒有意義,所以其結果通常(&>)被定向至/dev/null
2.先執(zhí)行命令,后判斷退出狀態(tài)碼是否為0
COMMAND
retval=$? if [ $? -eq 0 ] ; then
測試表達式:
(1) 整數(shù)測試;例如:1<2
(2) 字符串測試;例如:比較字符串相等與否
(3) 文件測試;例如:判斷文件類型
整數(shù)測試:A, B;需要雙目操作符;
A -gt B: 大于
A -ge B: 大于和等于
A -eq B: 等于
A -lt B: 小于
A -le B: 小于等于
A -ne B: 不等于
符合為真,否則為假
注意:命令執(zhí)行結果和狀態(tài)返回結果不一樣,需要判斷。
字符串測試:A, B
A > B
A < B
A >= B
A <= B
A == B或A = B:等值比較
A != B: 不等于
-z A: 判斷A是否為空;空則為真,不空則假;
-n A:判斷A是否不空;不空則為值,空則為假;
[ $A = $B ]
"$A" =~ PATTERN
如果變量A中給定的字符串能被模式匹配即為真,否則為假
例如:過濾fdisk -l 結果的字符串
#disk=/dev/sda #[[ $dsk=~/dev/sd[a-z] ]] 變量和模式匹配 #echo $? 0 為真 #disk=/dev/xda #[[ $disk =~ /dev/sd[a-z] ]] 變量和模式不匹配 #echo $? 1 為假
文件測試:$file
-e $file: 是否存在;存在則為真;
-a $file: 同上;棄用;
-f $file: 文件是否存在,且為普通文件;
-d $file: 是否存在且為目錄;
-h $file: 是否存在且為符號鏈接文件;
-L $file:同上
-b $file: 是否存在且為塊設備文件;
-c $file: 是否存在且為字符設備文件;
-S $file: 是否存在且為套接字文件:
-p $file: 是否存在且為管道文件;
-r $file: 當前用戶對此文件是否擁有讀權限;
-w $file: 寫
-x $file: 執(zhí)行權限;
-u $file: 文件是否擁有suid權限;
-g $file:文件是否擁有sgid權限;
-k $file: 文件是否擁有sticky權限;
-O $file: 當前用戶是否為文件的屬主;
-G $file: 當前用戶是否屬于文件的屬組;
-N $file: 文件自從上一次被讀取之后,是否被修改過;
$f1 -nt $f2: 文件f1是否比文件f2新;
$f1 -ot $f2: 文件f1是否比文件f2舊;
$f1 -ef $f2: f1和f2是否為同一個文件的硬鏈接;
練習:寫一個腳本,傳遞一個文件路徑參數(shù)給腳本
(1) 存在,則顯示有此文件;
(2) 否則,則顯示無此文件
#!/bin/bash if [ -e $1 ] ; then echo "$1 exist" else echo "$1 is not exist" fi
練習:寫一個腳本,傳遞一個文件路徑參數(shù)給腳本
(1) 如果腳本無參數(shù),則顯示必須給至少一個參數(shù),退出腳本;退出碼5;
(2) 路徑指向的文件如果不存在,則直接退出腳本;退出碼為6;
(3) 判斷文件類型:
(a) 如果是普通文件,則顯示為"common file";
(b) 如果是目錄,則顯示為"directory";
(c) 如果是符號鏈接,則顯示為"symbolic link file";
(d) 如果是塊設備,則顯示為“block device file";
(e) 如果是字符設備,則顯示為"character device file";
(f) 否則,則顯示為“unkown”;
#!/bin/bash if [ $# -lt 1 ] ; then echo "you mast input a number" exit 5 if [ ! -e $1 ] ; then echo "the file is not exist" exit 6 if [ -f $1 ] ; then echo "$1 is commonfile" elif [ -d $1 ] ; then echo "$1 is directory" elif [ -L $1 ] ; then echo "$1 is symbolic link file" elif [ -b $1 ] ; then echo "$1 is block device file" elif [ -c $1 ] ; then echo "$1 is character device file" else echo "$1 is unknow" fi
練習:寫一個腳本,其使用格式如下所示(其中所有的script.sh均為用戶給定的腳本名稱,其要跟隨腳本名稱變化):
script.sh {start|stop|restart|status}
(1) 調(diào)用時至少傳遞一個參數(shù);否則,則顯示幫助信息,并退出腳本;
(2) 如果參數(shù)為“start”, 則創(chuàng)建空文件/var/lock/subsys/script.sh,并顯示“starting script.sh successfully.”;
(3) 如果參數(shù)為“stop”,則刪除空文件/var/lock/subsys/script.sh,并顯示“stopping script.sh successfully.”;
(4) 如果參數(shù)為“restart”,則刪除空文件/var/lock/subsys/script.sh,并顯示“stopping script.sh successfully.”;而后重新創(chuàng)建之,并顯示“restarting script.sh successfully.”;
(5) 如果參數(shù)為“status”,則
(a) 如果文件/var/lock/subsys/script.sh文件存在,則顯示“running”;
(b) 否則,則顯示為"stopped"
(6) 其它任意參數(shù),均顯示幫助信息后退出;幫助信息格式為命令使用格式;
#!/bin/bash # # chkconfig: 2345 95 5 # description: test service script # prog=`basename $0` lockfile=/var/lock/subsys/$prog if [ $# -lt 1 ]; then echo "Usage: $prog {start|stop|restart|status}" exit 1 fi if [ "$1" == 'start' ]; then if [ -e $lockfile ]; then echo "$prog is aleady running." exit 1 else touch $lockfile echo "Starting $prog succefully." fi elif [ "$1" == 'stop' ]; then if [ -e $lockfile ]; then rm -f $lockfile echo "Stopping $prog succefully." else echo "$prog is not running." exit 1 fi elif [ "$1" == 'restart' ]; then if [ -e $lockfile ]; then rm -f $lockfile echo "Stopping $prog succefully." touch $lockfile echo "Starting $prog succefully." else touch $lockfile echo "Starting $prog succefully." fi elif [ "$1" == 'status' ];then if [ -e $lockfile ];then echo "$prog is running." else echo "$prog is stopped." fi else echo "Usage: $prog {start|restart|status|stop}" exit 1 fi
條件測試語法:
單分支:
if CONDITION; then CMD1 CMD2 ... fi
例如:求100以內(nèi)所有偶數(shù)之和;遍歷100以內(nèi)所有正整數(shù);
#!/bin/bash declare i sum=0 for i in {1..100} ; do if [[ $[$i%2] -eq 0 ]] ; then sum=$(($sum+$i)) fi done echo $sum
例如:傳遞一個參數(shù)給腳本,而后以此參數(shù)為用戶名,添加此用戶;
#!/bin/bash
if [ $# -ge 1 ];then
useradd $1
fi
if可以嵌套:
if CONDITION1; then if CONDITION2; then CMD fi fi
例如:傳遞一個參數(shù)給腳本,而后以此參數(shù)為用戶名,不存在時,則添加此用戶;
條件取反:
! CONDITION
#!/bin/bash 至少有個參數(shù) if [ $# -ge 1 ];then if ! id $1 &>/dev/null;then 條件取反 useradd $1 fi fi
if條件判斷為真才能執(zhí)行then下面的步驟
id $1 的狀態(tài)如果是0,表示執(zhí)行狀態(tài)成功了,取反后條件是假,then就不執(zhí)行
id $1 的執(zhí)行狀態(tài)如果是1,表示執(zhí)行狀態(tài)是失敗的,取反后條件判斷是真,then就開始執(zhí)行
練習:寫一個腳本
(1) 添加用戶testuser1-tuser10;
(2) 用戶不存在時才添加;
(3) 統(tǒng)計真正添加的用戶數(shù);
#!/bin/bash # declare -i newusers=0 for i in {1..10}; do if ! id testuser$i &> /dev/null; then useradd testuser$i let newusers++ fi done echo "New users: $newusers."
練習: 寫一個腳本
(1) 用ping命令測試172.16.100.X內(nèi)的所有主機;
(2) 將在線的主機輸出出來;
#!/bin/bash # for i in {1..254}; do if ping -c1 -w1 172.16.100.$i &> /dev/null; then echo "172.16.100.$i is up." fi done
雙分支結構:
if CONDITION-TRUE; then 分支1 else 分支2 fi
練習1: 寫一個腳本
(1) 用ping命令測試172.16.100.X內(nèi)的所有主機;
(2) 將所有主機的在線狀態(tài)輸出出來;
#!/bin/bash for i in {1..254}do if ping -c1 -w1 172.16.100.$i &>/dev/null;then echo "172.16.100.$i is up" else echo "172.16.100.$i is down" fi done
練習:寫一個腳本
(1) 傳遞兩個整數(shù)參數(shù)給腳本;
(2) 返回其較大一個;
#!/bin/bash declare -i max=0 for i in $* ; do if [ $i -gt $max ] ; then max=$i fi done echo $max
練習:寫一個腳本
(1) 傳遞兩個以上的整數(shù)給腳本;
(2) 返回其較大者;
#!/bin/bash # declare -i max=0 for i in $*; do if [ $i -gt $max ]; then max=$i fi done echo "max: $max."
練習: 寫一個腳本
(1) 取得當前的主機名;
(2) 如果當前的主機名為localhost,則將其修改為oracle;否則,顯示其名稱;
#!/bin/bash hostname=`hostname` if [ "$hostname" == 'localhost' ]; then hostname oracle echo "oracle" > /proc/sys/kernel/hostname fi
練習:寫一個腳本
(1) 傳遞兩個文本文件路徑給腳本;
(2) 顯示兩個文件中空白行數(shù)較多的文件及其空白行數(shù);
(3) 顯示兩個文件中總行數(shù)較多的文件及其行數(shù);
#!/bin/bash if [ $# -ge 2 ] ; then if [[ $(wc -l $1|cut -d" " -f1 ) -gt $(wc -l $2| cut -d" " -f1 ) ]] ; then if [[ $(grep "^$" $1 | wc -l) -gt $(grep "^$" $2 | wc -l) ]] ; then echo "the more space line file is $1 " echo "the file space line is $(grep "^$" $1 | wc -l)" else echo "the more space line file is $2 " echo "the file space line is $(grep "^$" $2 | wc -l)" fi echo "the more line file is $1 " echo "the line have $(wc -l $1)" else echo "the more line file is $2 " echo "the line have $(wc -l $2)" fi fi
練習:寫一個腳本
(1) 傳遞一個參數(shù)給腳本,此參數(shù)為用戶名;
(2) 如果用戶存在,則執(zhí)行如下任務
(a) 如果用戶的id號小于500,顯示其為管理員或系統(tǒng)用戶;
(b) 否則,顯示其為普通用戶;
(3) 如果用戶不存在,則添加之;
#!/bin/bash # if id $1 &> /dev/null; then userid=`id -u $1` if [ $userid -lt 500 ]; then echo "$1 is sysadmin or sysuser." else echo "A common user." fi else useradd $1 if [ $? -eq 0 ];then echo "Add user $1." else echo "Cannot add $1." fi fi
多分支的if語句:
if CONDITION1-TRUE; then 分支1 elif CONDITION2-TRUE; then 分支2 elif CONDITION3-TRUE; then 分支3 ... else 分支n fi
練習:傳遞一個參數(shù)給腳本
如果參數(shù)為quit,則顯示說要退出腳本;
如果參數(shù)為yes,則顯示說繼續(xù);
否則,則顯示為無法識別;
#!/bin/bash if [[ "$1" == 'quit' ]] ; then echo "quit" elif [[ "$1" == 'yes' ]] ; then echo "yes" else echo "unkown" fi
練習:傳遞一個用戶名參數(shù)給腳本
(1) 如果用戶的id號為0,則顯示為管理員;
(2) 如果用戶的id號大于6000,則顯示為guest;
(3) 如果用戶的id號大于500,則顯示為普通用戶;
(4) 如果用戶的id號大于0, 則顯示為系統(tǒng)用戶;
(5) 否則,無法識別;
#!/bin/bash if id $1 &/dev/null ; then userid=`id -u $1` if [ $userid -eq 0 ] ; then echo "$1 is sysadmin" elif [ $userid -gt 60000 ] ; then echo "$1 is a guest user" elif [ $userid -gt 500 ] ; then echo "$1 is a common user" elif [ $userid -gt 0 ] ; then echo "$1 is a system user" else echo "$1 is unknown " fi
練習3:寫一個腳本;
(1) 傳遞一個磁盤設備文件給腳本;
(2) 判斷此設備是否存在;如果存在,則清除此設備上的所有分區(qū);
(3) 否則,則無此設備;
#!/bin/bash if fdisk -l $1 ; then dd if=/dev/zero of=$1 bs=512 count=1 else echo "no such device" fi
組合測試條件1:
給條件添加邏輯操作符;
或, -o: [ -z "$hostname" -o "$hostname" == 'localhost' ]
與, -a: [ $uid -gt 0 -a $uid -lt 500 ]
非:[ ! EXPRESSION ]
練習:寫一個腳本,取得當前的主機名,判斷
(1) 如果主機名為空或為"localhost",則將其命名為stuX.oracle.com;
(2) 否則,則顯示主機名即可;
#!/bin/bash # hostname=`hostname` if [ "$hostname" == 'localhost' -o -z "$hostname" ]; then hostname stu100.oracle.com #echo "stu100.oracle.com" > /proc/sys/kernel/hostname else echo "The hostname is: $hostname." fi
練習:寫一個腳本,傳遞一個參數(shù)給腳本;此參數(shù)為用戶名
(1) 如果用戶不存在,則直接退出腳本;
(2) 如果用戶存在,
id=0,則顯示為“system admin”
0<id<500,則顯示為“system user”
id>=500,則顯示為“Common user.”
#!/bin/bash # if ! id $1 &> /dev/null; then echo "No such user." exit 1 fi uid=$(id -u $1) if [ $uid -eq 0 ]; then echo "Sys Admin." elif [ $uid -gt 0 -a $uid -lt 500 ];then echo "Sys User." else echo "Common User." fi
練習:寫一個腳本,傳遞一個參數(shù)給腳本;此參數(shù)為用戶名
(1) 如果用戶不存在,則直接退出腳本;
(2) 如果用戶的id號大于等于500,且其shell為“以sh結尾的”類型,則顯示“a user can log system.”;否則,顯示用戶無法登錄;
#!/bin/bash # if ! id $1 &> /dev/null; then echo "No such user." exit 1 fi if [[ `id -u $1` -ge 500 ]] && [[ `grep "^$1\>" /etc/passwd | cut -d: -f7` =~ /bin/.*sh$ ]]; then echo "a user can log system." else echo "a user cannot log." fi
組合測試條件2:
短路操作符
與:COMMAND1 && COMMAND2
COMMAND1的退出狀態(tài)如果為假,則COMMAND2不用運行,即可有最終結果;
或:COMMAND1 || COMMAND2
COMMAND1的退出狀態(tài)如果為真,則COMMAND2不用運行,即可有最終結果;
非:! COMMAND
[ ! -d /tmp/test ] && mkdir /tmp/test^C [ -d /tmp/test ] || mkdir /tmp/test
練習:寫一個腳本,完成如下任務:
(1) 如果httpd進程或nginx進程處于運行中,則顯示“web server started.”,并顯示其監(jiān)聽的端口;
(2) 否則顯示“no web server.”;
if pidof httpd &> /dev/null && pidof nginx &> /dev/null;
交互式腳本:
read [OPTIONS] [name ...]
-p "PROMPT"
-t #: 超時時長
給變量以默認值:
[ -z "$VAR" ] && VAR=VALUE
練習:顯示如下菜單給用戶
cpu) show cpu infomation;
mem) show memory infomation;
disk) show disk infomation;
*) quit
提示用戶鍵入選項:
(1) cpu: 顯示CPU相關的信息
(2) mem: 顯示內(nèi)存相關的信息
(3) disk: 列出磁盤設備
(4) 其它任何信息,即為退出腳本
#!/bin/bash # cat << EOF cpu) show cpu infomation; mem) show memory infomation; disk) show disk infomation; *) quit ========================================================= EOF read -p "Your choice: " choice if [[ "$choice" == 'cpu' ]]; then lscpu elif [[ "$choice" == 'mem' ]]; then free -m elif [[ "$choice" == 'disk' ]]; then fdisk -l /dev/sd[a-z] else echo "quit" exit 0 fi
case語句:
簡潔版的多分支if語句;
語法格式:
case 變量引用 in PATTERN1) 分支1 ;; PATTERN2) 分支2 ;; ... *) 分支n ;; esac
PATTERN可使用通配符:
*:任意長度的任意字符
?: 任意單個字符
[]:指定范圍內(nèi)的任意單個字符
a|b: a或者b
練習:寫一個腳本,使用tar工具把/etc目錄備份至/backup目錄中,名字為/backup/etc-日期時間.tar.{xz|bz2|gz};
(1) 顯示如下菜單
xz) xz compress tool
gzip) gzip compress tool
bzip2) bzip2 compress tool
*) wrong choice and quit
(2) 根據(jù)用戶選擇的工具,執(zhí)行相應操作;如果用戶沒有鍵入任何數(shù)據(jù),則默認使用xz;
#!/bin/bash cat<<EOF xz)xz compress tool gzip)gzip compress tool bzip2)bzip2 compress tool *)wrong choice and quit ======================================================= EOF read -t 5 -p "pls input the choice:" command [ -z $command ] && command="xz" ! [ -d /backup ] || mkdir /backup file_path=/backup/etc"-$(date +%Y%m%d%H%M).tar" echo $file_path case $command in "xz") echo "xz" #tar -Jcf $file_path.xz /etc/* ;; "gzip") echo "gzip" #tar -zcf $file_path.gz /etc/* ;; "bzip2") echo "bzip2" #tar -jcf $file_path.bzip2 /etc/* ;; *) echo "wrong choice" ;; esac
練習:使用case語句編寫一個服務腳本框架
#!/bin/bash # # chkconfig: # description: # prog=`basename $0` lockfile=/var/lock/subsys/$prog case $1 in "start") if [ -e $lockfile ];then echo "$prog is aleady running" exit 1 else touch $lockfile echo "Starting $prog succefully" fi ;; "stop") if [ -e $lockfile ];then rm -f $lockfile echo "Stopping $prog succefully" else echo "$porg is not running" exit 1 fi ;; "restart") if [ -e $lockfile ];then rm -f $lockfile echo "Stopping $prog succefully" touch $lockfile echo "Starting $prog succefully" else touch $lockfile echo "Starting $prog succefully" fi ;; "status") if [ -e $lockfile ];then echo "$prog is running" else echo "$prog is stopped" fi ;; *) echo "Usage: $prog {start|restart|status|stop}" exit 1 ;; esac
bash中生成偽隨機數(shù):$RANDOM
0-32767
練習:生成10個隨機數(shù),返回其最大值;
#!/bin/bash declare -i max=0 for i in {1..10};do random=$RANDOM LIST="$LIST $random" if [ $random -ge $max ];then max=$random fi done echo "List Number:$LIST" echo "Max Number:$max"
練習:從所有同學中隨機挑選一個學號;
#!/bin/bash i=$[$RANDOM%36+1] j=$[$RANDOM%36+1] while [ $i -ne $j ] ; do echo $i echo $j break done # echo $[`date +%N`%36+1] # echo $[`head /dev/urandom | cksum |cut -d" " -f1`%36+1]
while、until循環(huán)和函數(shù):
練習:使用for循環(huán),打印九九乘法表
#!/bin/bash # for i in {1..9}; do for j in `seq 1 $i`; do echo -n -e "${j}x${i}=$[$i*$j]\t" done echo done
while循環(huán):
while CONDITION; do
循環(huán)體
循環(huán)控制變量的修正表達式
done
當CONDITION為“真”進入循環(huán),直到“假”退出循環(huán);
練習:計算100以內(nèi)所有偶數(shù)之和;
#!/bin/bash # declare -i i=1 declare -i evensum=0 while [ $i -le 100 ]; do if [ $[$i%2] -eq 0 ]; then let evensum+=$i fi let i++ done echo $evensum
until循環(huán):
until CONDITION; do
循環(huán)體
循環(huán)控制變量修正表達式
done
當CONDITION為“假”時進入循環(huán);為“真”退出循環(huán);
練習:計算100以內(nèi)所有偶數(shù)之和;
#!/bin/bash # declare i=1 declare evensum=0 until [ $i -gt 100 ]; do if [ $[$i%2] -eq 0 ]; then let evensum+=$i fi let i++ done echo $evensum
練習:分別使用while和until循環(huán)實現(xiàn)添加10個用戶:myuser1-myuser10
#!/bin/bash # declare -i i=1 declare -i j=0 until [ $i -gt 10 ]; do if ! id myuser$i &> /dev/null; then useradd myuser$i let j++ fi let i++ done echo "Add users [total]: $j."
練習:打印九九乘法表,要求內(nèi)外層循環(huán)分別使用while或until;
#!/bin/bash declare i=1 declare j=1 while [ $i -le 9 ] ; do while [ $j -le 9 ] ; do if [ $j -gt $i ] ; then break fi echo -e -n "${j}x${i}=$[$i*$j]\t" let j++ done echo let j=1 let i++ done
循環(huán)控制命令:
break:提前退出循環(huán);
break [N]: 退出N層循環(huán);N省略時表示退出break語句所在的循環(huán);
continue: 提前結束本輪循環(huán),而直接進入下輪循環(huán);
continue [N]:提前第N層的循環(huán)的本輪循環(huán),而直接進入下輪循環(huán);
while CONDITION; do
CMD1
if CONDITION2; then
break [N]
fi
CMD2
...
done
死循環(huán):
while true; do
循環(huán)體
done
until false; do
循環(huán)體
done
練習:寫一個腳本,判斷給定的用戶是否登錄了當前系統(tǒng);
(1) 如果登錄了,則腳本終止;
(2) 每5秒種,查看一次用戶是否登錄;
方法一:使用until循環(huán)
#!/bin/bash # declare -i status=0 who | grep "centos" &> /dev/null status=$? until [ $status -eq 0 ]; do sleep 5 who | grep "centos" &> /dev/null status=$? done echo "centos is logged on."
方法二:簡化版
#!/bin/bash # declare -i status=0 until who | grep "centos" &> /dev/null; do sleep 5 done echo "centos is logged on."
方法三:使用死循環(huán)
#!/bin/bash # while true; do who | grep "centos" &> /dev/null if [ $? -eq 0 ];then break fi sleep 5 done echo "centos is logged."
while的特殊用法:遍歷指定文件的每一行
while read line; do
循環(huán)體
done < /path/from/somefile
練習:找出其UID為偶數(shù)的所有用戶的用戶名;并顯示其ID號;
#!/bin/bash # file=/etc/passwd while read line; do userid=`echo $line | cut -d: -f3` if [ $[$userid%2] -eq 0 ]; then echo $line | cut -d: -f1,3 fi done < $file
練習:輸出給定的文件的偶數(shù)行的行號,以及其行內(nèi)信息統(tǒng)統(tǒng)改為大寫字母輸出;
#!/bin/bash declare -i i=1 while read line; do if [ $[$i%2] -eq 0 ]; then echo -n "$i " echo $line | tr 'a-z' 'A-Z' fi let i++ done < /path/from/somefile
練習:顯示如下菜單給用戶
cpu) cpuifno
mem) memory infomation
disk) disk infomation
quit) quit
(1) 用戶給定的選項后,顯示相應的信息;而后提示用戶再次選擇;
(2) 非正確選擇也提示用戶重新選擇,并說明,如果想退出請輸入"quit";
#!/bin/bash # while true; do cat << EOF cpu) cpu mem) memory disk) disk quit) quit EOF read -p "Your choice: " choice case $choice in cpu) lscpu ;; mem) free ;; disk) fdisk -l /dev/sd[a-z] ;; quit) break ;; esac done
函數(shù):function
過程式編程:代碼重用
模塊化編程;
簡潔
語法:
function f_name {
函數(shù)體
}
f_name() {
函數(shù)體
}
調(diào)用:使用函數(shù)名
函數(shù)名出現(xiàn)的地方,會被自動替換為函數(shù)代碼;
練習:利用函數(shù)改寫此前的服務腳本:
#!/bin/bash # prog=`basename $0` lockfile=/var/lock/subsys/$prog start() { if [ -e $lockfile ]; then echo "$prog is already running." else touch $lockfile [ $? -eq 0 ] && echo "Starting $prog finished." fi } stop() { if [ -e $lockfile ]; then rm -f $lockfile [ $? -eq 0 ] && echo "Stoping $prog finished." else echo "$prog is stopped yet." fi } case $1 in "start") start ;; "stop") stop ;; "restart") stop start ;; *) echo "Usage: $prog {start|stop|restart}" exit 1 esac
函數(shù)的返回值:
函數(shù)的執(zhí)行結果返回值:
函數(shù)中使用打印語句:echo, printf
函數(shù)體中OS命令執(zhí)行結果的輸出
函數(shù)的退出狀態(tài)碼:
默認取決于函數(shù)體執(zhí)行的最后一個命令的退出狀態(tài)碼;
自定義退出狀態(tài)碼:
return [0-255]
注意:函數(shù)體運行時,一旦遇到return語句,函數(shù)即返回;
函數(shù)可接受參數(shù):
傳遞參數(shù)給函數(shù):調(diào)用函數(shù)時,在函數(shù)名后給出參數(shù)列表即可;例如“testfunc arg1 arg2 arg3”
在函數(shù)體中可使用$1, $2,...來調(diào)用傳遞過來的各參數(shù);
可使用類似腳本的特殊變量:
$*, $@: 一次性獲取參數(shù)列表:
$#: 參數(shù)的個數(shù)
判定用戶輸入用戶名是否正確與否分別執(zhí)行不同操作
#!/bin/bash # showuserinfo() { [ $# -lt 1 ] && return 1 ! id $1 &> /dev/null && return 2 grep "^$1\>" /etc/passwd | cut -d: -f7 [ $? -eq 0 ] && return 0 || return 3 } while true; do read -p "Enter a username: " username [ "$username" == 'quit' ] && break showuserinfo $username [ $? -ne 0 ] && echo "There is something wrong." done
練習:利用函數(shù)實現(xiàn)打印九九乘法表;
#!/bin/bash func() { declare i=1 declare j=1 while [ $i -le 9 ] ; do while [ $j -le 9 ] ; do if [ $j -gt $i ] ; then break fi echo -e -n "{$j}x$i=$[$i*$j]\t" let j++ done echo let j=1 let i++ done } func
練習:寫一個腳本,完成如下功能(使用函數(shù)):
1、提示用戶輸入一個可執(zhí)行命令;
2、獲取這個命令所依賴的所有庫文件(使用ldd命令);
3、復制命令至/mnt/sysroot/對應的目錄中
解釋:假設,如果復制的是cat命令,其可執(zhí)行程序的路徑是/bin/cat,那么就要將/bin/cat復制到/mnt/sysroot/bin/目錄中,如果復制的是useradd命令,而useradd的可執(zhí)行文件路徑為/usr/sbin/useradd,那么就要將其復制到/mnt/sysroot/usr/sbin/目錄中;
4、復制各庫文件至/mnt/sysroot/對應的目錄中;
#!/bin/bash # target=/mnt/sysroot [ -d $target ] || mkdir $target preCmd() { if which $1 &> /dev/null; then cmdpath=$(which --skip-alias $1) return 0 else echo "No such command." return 1 fi } cmdCopy() { cmddir=$(dirname $cmdpath) [ -d $target/$cmddir ] || mkdir -p $target/$cmddir [ -f $target/$cmdpath ] || cp $1 $target/$cmddir return 0 } libCopy() { for lib in $(ldd $1 | grep -E -o "/[^[:space:]]+"); do libdir=$(dirname $lib) [ -d $target/$libdir ] || mkdir -p $target/$libdir [ -f $target/$lib ] || cp $lib $target/$libdir done return 0 } main() { while true; do read -p "Plz enter a command(quit for quiting): " cmd [ "$cmd" == 'quit' ] && break preCmd $cmd if [ $? -eq 0 ]; then cmdCopy $cmdpath libCopy $cmdpath fi done } main
變量的作用域:
本地變量:整個腳本,在腳本的函數(shù)中也可調(diào)用,也可修改;
局部變量:函數(shù)調(diào)用的整個生命周期;
local VAR=VALUE
函數(shù)遞歸:
函數(shù)直接或間接調(diào)用函數(shù)自身;
1 1 2 3 5 8 13
階乘:10!
n(n-1)!
n(n-1)(n-2)!
階乘函數(shù):
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
echo 1
else
echo $[$1*$(fact $[$1-1])]
fi
}
下一篇接:Bash Shell腳本編程筆記總結(二)
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。