bash之條件測試:
if/then結構
條件測試(CONDITION):
test EXPRESSION:測試條件表達式正確否
[ EXPRESSION ]
[[ EXPRESSION ]]
COMMAND
測試表達式:
1)整數測試
2)字符串測試
3)文件測試
整數測試:A, B
A -gt B: 大於
A -ge B: 大於等於
A -eq B: 等於
A -lt B: 小於
A -le B: 小於等於
A -ne B: 不等於
例:
字符串測試:A, B
A > B
A < B
A >= B
A <= B
A == B或A = B: 等值比較
A != B: 不等於
-z A: 判斷A是否為空,空則為真,不空為假
-n A: 判斷A是否不空,不空為真,空為假
條件取反:
! CONDITION
條件測試語法:
單分支:
if CONDITION; then
CMD1
CMD2
fi
例:傳遞一個參數給test.sh,判斷是否為偶數,是則打印,否則不打印
test.sh 5
#!/bin/bash
shuzi=$1
if [ $[$shuzi%2] -eq 0 ];then
echo $shuzi
fi
條件表達式為雙中括號[[ $shuzi%2 -eq 0 ]]也可以
bash -n test.sh
檢查腳本有無語法錯誤
bash -x test.sh 10
調試執行,一步一步執行,打印執行步驟,最后打印執行結果
例:傳遞一個參數給腳本,而后以此參數為用戶名,添加此用戶
useradd.sh
#!/bin/bash
username=$1
if ! id $username ;then
useradd $username
fi
執行bash -n useradd.sh檢查腳本是否存在語法錯誤
bash -x useradd.sh aaa
打印執行過程,最終打印執行結果
if可以嵌套:
if CONDITION; then
if CONDITION2; then
CMD
fi
fi
條件取反:
! COMMAND
雙分支:
if CONDITION; then
分支1
else
分支2
fi
練習2:
傳遞兩個整數給腳本,返回其較大者
test.sh
#!/bin/bash
if $1 -gt $2;then
echo $1
else
echo $2
fi
bash -n
練習3:寫一個腳本
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 "$1 is a common user"
fi
else
useradd $1
if [ $? -eq 0 ];then
echo "Add user $1"
else
echo "Fail to add $1"
fi
fi
&<:標准輸出和錯誤輸出都輸出進黑洞/dev/null
useradd命令是管理員才能使用的命令,所以有可能執行失敗,故用判斷$?
多分支的if語句:
if CONDITION1-TRUE;then
分支1
elif CONDITION2-TRUE;then
分支2
elif CONDITION3-TRUE;then
分支3
...
else
分支n
fi
例:
練習1:傳遞一個參數給腳本
如果參數為quit,則顯示說要退出腳本;
如果參數為yes,則顯示說繼續;
否則,則顯示為無法識別;
test.sh
#!/bin/bash
if [ $1 == "quit" ];then
exit
elif [ $1 == "yes" ];then
echo "continue"
else
echo "not find age"
fi
練習2:傳遞一個用戶名參數給腳本
(1) 如果用戶的id號為0,則顯示為管理員;
(2) 如果用戶的id號大於6000,則顯示為guest;
(3) 如果用戶的id號大於500,則顯示為普通用戶;
(4) 如果用戶的id號大於0, 則顯示為系統用戶;
(5) 否則,無法識別;
練習3:寫一個腳本;
(1) 傳遞一個磁盤設備文件給腳本;
(2) 判斷此設備是否存在;如果存在,則清除此設備上的所有分區;
(3) 否則,則無此設備;
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 ]
條件測試:
文件u測試:$file
-e $file:是否存在,存在則為真 [ -e /tmp/aaa ]
-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:文件自從上一次被讀取之后,是否被修改過
$f1 -nt $f2:文件f1是否比文件f2新
$f1 -ot $f2:文件f1是否比文件f2舊
$f1 -ef $f2:f1和f2是否為同一個文件的硬鏈接
練習:寫一個腳本,傳遞一個文件路徑參數給腳本
(1) 存在,則顯示有此文件;
(2) 否則,則顯示無此文件
練習:寫一個腳本,傳遞一個文件路徑參數給腳本
(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 file"
elif [ -b $1 ];then
echo "block device"
elif [ -c $1 ];then
echo "character device"
else
echo "unknown type."
fi
$#是腳本傳遞的參數個數
練習:寫一個腳本,其使用格式如下所示(其中所有的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
#
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
組合測試條件:
給條件添加邏輯操作符:
或:-o: [ -z "$hostname" -o "$hostname" == 'localhost' ]
-z "$hostname": 判斷字符串是否為空
與:-a: [ $uid -gt 0 -a $uid -lt 500 ]
非:[ ! EXPRESSION ]
練習:寫一個腳本,取得當前的主機名,判斷
(1) 如果主機名為空或為"localhost",則將其命名為stuX.lianshu.com;
(2) 否則,則顯示主機名即可;
#!/bin/bash
hostname=`hostname`
if [ -z "$hostname" -o "$hostname" == "localhost"];then
hostname stuX.lianshu.com
#echo "stuX.lianshu.com" > /proc/sys/kernel/hostname
else
echo "The hostname is: $hostname"
fi
練習2:寫一個腳本,傳遞一個參數給腳本;此參數為用戶名
(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
練習3:寫一個腳本,傳遞一個參數給腳本;此參數為用戶名
(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
^$1\>: (^root\>)以root開頭,且詞尾錨定,排除包含root字符的,例如rootab
=~為模式匹配
組合測試條件:短路操作符
與:COMMAND1 && COMMAND2
COMMAND1的退出轉態結果為假,則COMMAND2不用運行,則有最終結果
或:COMMAND1 || COMMAND2
COMMAND1的退出轉態結果為真,則COMMAND2不用運行,則有最終結果
非:! COMMAND
例:[ ! -d /tmp/test ] && mkdir /tmp/test
[ -d /tmp/test ] || mkdir /tmp/test
練習4:寫一個腳本,完成如下任務:
(1) 如果httpd進程或nginx進程處於運行中,則顯示“web server started.”,並顯示其監聽的端口;
(2) 否則顯示“no web server.”;
if pidof httpd &> /dev/null || pidof nginx &> /dev/null;then
echo "web server started."
else
echo "no web server."
交互式腳本:
read [OPTIONS] [name ...]
-p "PROMPT": 輸入過程中,想刪除,則必須按ctrl+delete,單獨的delete鍵是執行不了刪除操作的
read -p "pls input:" aa
-t #: 超時時間
read -p "pls input:" -t 2 aa
給變量以默認值:
[ -z "$VAR" ] && VAR=VALUE
練習1:顯示如下菜單給用戶
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
case語句:
簡潔版的多分支if語句
語法格式:
case 變量引用 in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
...
*)
分支n
;;
esac
PATTERN可使用通配符:
*:任意長度的任意字符
?: 任意單個字符
[]:指定范圍內的任意單個字符
a|b: a或者b
練習1:寫一個腳本,使用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) 根據用戶選擇的工具,執行相應操作;如果用戶沒有鍵入任何數據,則默認使用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
