一、if語句:
單分支:
if CONDITION-TRUE; then
分支
fi
雙分支:
if CONDITION-TRUE; then
分支1
else
分支2
fi
多分支:
if CONDITION1-TRUE; then
分支1
elif CONDITION2-TRUE; then
分支2
...
else
分支n
fi
二、條件測試:
test EXPRESSION
[ EXPRESSION ]
` EXPRESSION `
COMMAND
2.1 測試表達式:
(1) 整數測試;
(2) 字符串測試;
(3) 文件測試
2.2 整數測試:A, B
A -gt B: 大於
A -ge B: 大於等於
A -eq B: 等於
A -lt B: 小於
A -le B: 小於等於
A -ne B: 不等於 not equal to
2.3 字符串測試:A, B
A > B
A < B
A >= B
A <= B
A == B或A = B:等值比較
A != B: 不等於
-z A: 判斷A是否爲空;空則爲真,不空則假;
-n A:判斷A是否不空;不空則爲真,空則爲假;
=~
"$A" =~ PATTERN
如果變量A中保存的字符串能被PATTERN所匹配;即爲真;否則爲假;
2.4 文件測試:$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: 執行權限;
-u $file: 文件是否擁有suid權限;
-g $file:文件是否擁有sgid權限;
-k $file: 文件是否擁有sticky權限;
-O $file: 當前用戶是否爲文件的屬主;
-G $file: 當前用戶是否屬於文件的屬組;
-N $file: 文件自從上一次被讀取之後,是否被修改過;
例如:
# cp /etc/fstab /tmp/
# cat /tmp/fstab
# [ -N /tmp/fstab ]
# echo $?
1
# echo "hell world" >> /tmp/fstab
# [ -N /tmp/fstab ]
# echo $?
0
-s 測試文件是否不空,不空則爲真,空則爲假
$f1 -nt $f2: 文件f1是否比文件f2新;
$f1 -ot $f2: 文件f1是否比文件f2舊;
$f1 -ef $f2: f1和f2是否爲同一個文件的硬鏈接;
2.5 COMMAND用作條件:
(1) 使用命令執行結果;
(a) 使用命令引用
(b) 使用比較操作符
例如:
[ `id -u $username` -lt 500 ] userid=`id -u $username` [ $userid -lt 500 ]
(2) 使用命令的退出狀態碼
(a) 先運行命令;
(b) 退出狀態碼
引用方式兩種:
(a) if COMMAND; then
注意:COMMAND不能被命令引用;COMMAND的執行結果通常沒有意義,所以其結果通常(&>)被定向至/dev/null
(b) 先執行命令,後判斷退出狀態碼是否爲0
COMMAND
if [ $? -eq 0 ]
三、條件測試語法:
3.1 單分支:
3.1.1
if CONDITION; then
CMD1
CMD2
...
fi
例如:求100以內所有偶數之和;遍歷100以內所有正整數;
#!/bin/bash declare -i sum=0 for i in {1..100}; do if [[ $[$i%2] -eq 0 ]]; then let sum+=$i fi done echo "the sum of even is $sum"
練習1:傳遞一個參數給腳本,而後以此參數爲用戶名,添加此用戶;
方法一:
#!/bin/bash # if [ $# -ge 1 ]; then if ! id $1 &>/dev/null;then useradd $1 fi fi
方法二:
#!/bin/bash if !id $1 & >> null;then useradd $1 else echo "the user exists" fiif可以嵌套: if CONDITION1; then if CONDITION2; then CMD fi fi
3.1.2 條件取反:
! CONDITION
練習2:寫一個腳本
(1) 添加用戶testuser1-tuser10;
(2) 用戶不存在時才添加;
(3) 統計真正添加的用戶數;
#!/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."
練習3: 寫一個腳本
(1) 用ping命令測試172.16.100.X內的所有主機;
(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
3.2 雙分支:
if CONDITION-TRUE; then
分支1
else
分支2
fi
練習4: 寫一個腳本
(1) 用ping命令測試172.16.100.X內的所有主機;
(2) 將所有主機的在線狀態輸出出來;
#!/bin/bash #!/f [ $# -ge 1 ]; then if ! id $1 &>/dev/null;then useradd $1 fi fibin/bash # for i in {1..255};do if ping -c1 -w1 172.16.100.$i &>/dev/null;then echo the host: 172.16.100.$i is online else echo the host: 172.16.100.$i is offline fi done
練習5:寫一個腳本
(1) 傳遞兩個整數參數給腳本;
(2) 返回其較大一個;
#!/bin/bash if [ $1 -lt $2 ]; then echo $2 else echo $1 fi
練習6:寫一個腳本
(1) 傳遞兩個以上的整數給腳本;
(2) 返回其較大者;
#!/bin/bash # declare -i max=0 for i in $*; do if [ $i -gt $max ]; then max=$i fi done echo "max: $max."
練習7: 寫一個腳本
(1) 取得當前的主機名;
(2) 如果當前的主機名爲localhost,則將其修改爲www.magedu.com;否則,顯示其名稱;
#!/bin/bash source /etc/sysconfig/network (讀取HOSTNAME配置文件,讓變量$HOSTNAME可以直接引用) #echo $HOSTNAME [ "$HOSTNAME" == "localhost" ] && HOSTNAME="www.mage.com" #/bin/hostname $HOSTNAME (修改主機名,若在配置文件修改,可永久生效,但需要重啓;而hostname加newname可臨時修改;爲避免重啓,所以做臨時修改;而hostname前加/bin/;是因爲/bin/爲二進制程序配置文件庫;怕在腳本中直接用hostname修改不了) hostname $HOSTNAME echo $HOSTNAME 或者: #!/bin/bash source /etc/sysconfig/network if [ $HOSTNAME == localhost ] ; then HOSTNAME="www.mage.com" else echo $HOSTNAME fi hostname $HOSTNAME echo $HOSTNAME
練習8:寫一個腳本
(1) 傳遞兩個文本文件路徑給腳本;
(2) 顯示兩個文件中空白行數較多的文件及其空白行數;
(3) 顯示兩個文件中總行數較多的文件及其行數;
#!/bin/bash i=`grep "^$" $1 | wc -l` j=`grep "^$" $2 | wc -l` if [[ $i -gt $j ]]; then echo " the spaceline: $i" else echo "the spaceline: $j" fi k=`cat $1 | wc -l` L=`cat $2 | wc -l` if [[ $k -gt $L ]]; then echo "the file is $1 & the totalline is $k" else echo "the file is $L & the totalline is $L" fi
練習9:寫一個腳本
(1) 傳遞一個參數給腳本,此參數爲用戶名;
(2) 如果用戶存在,則執行如下任務
(a) 如果用戶的id號小於500,顯示其爲管理員或系統用戶;
(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
3.3 多分支的if語句:
if CONDITION1-TRUE; then
分支1
elif CONDITION2-TRUE; then
分支2
elif CONDITION3-TRUE; then
分支3
...
else
分支n
fi
練習10:傳遞一個參數給腳本
如果參數爲quit,則顯示說要退出腳本;
如果參數爲yes,則顯示說繼續;
否則,則顯示爲無法識別;
#!/bin/bash if [ "$1" == "quit" ];then 或者[ $1 == quit ] echo "exit" elif [ "$1" == "yes" ];then echo "continue" else echo "Not recognized" fi
練習11:傳遞一個用戶名參數給腳本
(1) 如果用戶的id號爲0,則顯示爲管理員;
(2) 如果用戶的id號大於6000,則顯示爲guest;
(3) 如果用戶的id號大於500,則顯示爲普通用戶;
(4) 如果用戶的id號大於0, 則顯示爲系統用戶;
(5) 否則,無法識別;
#!/bin/bash # if [ -z $1 ]; then #echo "Usage: $(basen" echo "Not recognized" exit 1 elif ! id $1 &> /dev/null; then #echo "Unknown....This isn't a user." echo "Not recognized" exit 2 else userid=$(id -u $1) if [ $userid -eq 0 ]; then echo "Admin user" elif [ $userid -gt 6000 ]; then echo "Guest user" elif [ $userid -gt 500 ] && [ $userid -le 6000 ]; then echo "Comon user" elif [ $userid -gt 0 ] && [ $userid -le 500 ]; then echo "System user" fi fi
或者
#!/bin/bash if [ $# -lt 1 ] ;then echo "please input a user name" exit 1 fi if id $1 &> /dev/null ; then uid=`id -u $1` else echo "no such user" exit 2 fi if [ "$uid" -eq 0 ] ;then echo "The user is administrator" elif [ "$uid" -gt 6000 ] ; then echo "The user is guest" elif [ "$uid" -gt 500 ] ; then echo "The user is common" elif [ "$uid" -gt 0 ] ; then echo "The user is system " else echo "Cannot found" fi
3.4 文件測試練習
練習12:寫一個腳本,傳遞一個文件路徑參數給腳本
(1) 存在,則顯示有此文件;
(2) 否則,則顯示無此文件
#!/bin/bash if [ -z $1 ];then echo "you entered nothing" exit 1 else if [ -e $1 ]; then echo "the file exists" else echo "the file doesn't exist" fi fi
練習13:寫一個腳本,傳遞一個文件路徑參數給腳本
(1) 如果腳本無參數,則顯示必須給至少一個參數,退出腳本;退出碼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 "At least one argument." exit 5 fi if [ ! -e $1 ]; then echo "No such file." exit 6 fi if [ -f $1 ]; then echo "common file." elif [ -d $1 ]; then echo "directory." elif [ -L $1 ]; then echo "Symbolic link." elif [ -b $1 ]; then echo "block device." elif [ -c $1 ]; then echo "character device." else echo "unkown type." fi
練習14:寫一個腳本,其使用格式如下所示(其中所有的script.sh均爲用戶給定的腳本名稱,其要跟隨腳本名稱變化):
script.sh {start|stop|restart|status}
(1) 調用時至少傳遞一個參數;否則,則顯示幫助信息,並退出腳本;
(2) 如果參數爲“start”, 則創建空文件/var/lock/subsys/script.sh,並顯示“starting script.sh successfully.”;
(3) 如果參數爲“stop”,則刪除空文件/var/lock/subsys/script.sh,並顯示“stopping script.sh successfully.”;
(4) 如果參數爲“restart”,則刪除空文件/var/lock/subsys/script.sh,並顯示“stopping script.sh successfully.”;而後重新創建之,並顯示“restarting script.sh successfully.”;
(5) 如果參數爲“status”,則
(a) 如果文件/var/lock/subsys/script.sh文件存在,則顯示“running”;
(b) 否則,則顯示爲"stopped"
(6) 其它任意參數,均顯示幫助信息後退出;幫助信息格式爲命令使用格式;
#!/bin/bash # # chkconfig: 2345 95 5 # description: test service script 此兩行爲開機啓動腳本格式;可以cp到腳本配置文件 /etc/init.d 裏面;但需要先給其權限;然後再拷貝;然後在命令行鍵入chkfig -add script.sh 運行;則可生效 # prog=`basename $0` $0是從當下目錄到其有$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
四、組合測試條件:
4.1 給條件添加邏輯操作符;
或, -o: [ -z "$hostname" -o "$hostname" == 'localhost' ]
與, -a: [ $uid -gt 0 -a $uid -lt 500 ]
非:[ ! EXPRESSION ]
練習15:寫一個腳本,取得當前的主機名,判斷 答案參照552練習4題;
(1) 如果主機名爲空或爲"localhost",則將其命名爲stuX.magedu.com;
(2) 否則,則顯示主機名即可;
#!/bin/bash # hostname=`hostname` if [ "$hostname" == 'localhost' -o -z "$hostname" ]; then hostname stu100.magedu.com #echo "stu100.magedu.com" > /proc/sys/kernel/hostname else echo "The hostname is: $hostname." fi
練習16:寫一個腳本,傳遞一個參數給腳本;此參數爲用戶名
(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) 注意:大寫UID在此處用可能有會衝突,也可找其他字母代替 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
練習17:寫一個腳本,傳遞一個參數給腳本;此參數爲用戶名
(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
或者
#!/bin/bash if [ $# -lt 1 ];then echo "At least one argument" exit 1 fi if ! id $1 &>/dev/null;then echo "the user does not exist" exit 2 fi if id $1 &>/dev/null;then if [[ `id -u $1` -ge 500 ]] && [[ `grep 'bash$' /etc/passwd | cut -d: -f7` ]];then echo "a user can log system" else echo "can not login" fi fi
4.2 組合測試條件:短路操作符
與:COMMAND1 && COMMAND2
COMMAND1的退出狀態如果爲假,則COMMAND2不用運行,即可有最終結果;
或:COMMAND1 || COMMAND2
COMMAND1的退出狀態如果爲真,則COMMAND2不用運行,即可有最終結果;
非:! COMMAND
[ ! -d /tmp/test ] && mkdir /tmp/test
[ -d /tmp/test ] || mkdir /tmp/test
練習18:寫一個腳本,完成如下任務:
(1) 如果httpd進程或nginx進程處於運行中,則顯示“web server started.”,並顯示其監聽的端口;
(2) 否則顯示“no web server.”;
(if pidof httpd &> /dev/null && pidof nginx &> /dev/null;)
#!/bin/bash h=`netstat -lntp | grep 'httpd' | cut -d':' -f4` n=`ss -tnlp | grep 'nginx' | cut -d":" -f2 | cut -d" " -f1` if pidof httpd &>/dev/null;then # netstat -tnlp | grep 'httpd' | cut -d':' -f4 echo "the httpd web server started" echo "the httpd listenning port is $h" elif pidof nginx &>/dev/null;then # ss -tnlp | grep 'nginx' | cut -d":" -f2 | cut -d" " -f1 # netstat -ntpl | grep 'nginx' | cut -d: -f2 | cut -d" " -f1 echo "the nginx web server started" echo "the nginx listenning port is $n" else echo "No web server" fi
上面是各種方法的組合,可以靈活轉換
五、交互式腳本:
read [OPTIONS] [name ...]
用法示例:
[root@node3 ~]# read A hello [root@node3 ~]# echo $A hello [root@node3 ~]# read A B C how old are you? [root@node3 ~]# echo $A how [root@node3 ~]# echo $C are you?
-p "PROMPT" 提示信息
-t #: 超時時長
給變量以默認值:
[ -z "$VAR" ] && VAR=VALUE
練習19:顯示如下菜單給用戶
cpu) show cpu infomation;
mem) show memory infomation;
disk) show disk infomation;
*) quit
提示用戶鍵入選項:
(1) cpu: 顯示CPU相關的信息
(2) mem: 顯示內存相關的信息
(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