shell編程:條件測試與比較(六)


條件測試方法綜述

 

test條件測試的簡單語法及測試

 

范例6-1 測試文件(在test命令中使用-f選項:文件存在且為不同文件則表達式成立)

[root@adminset ~]# test -f file && echo true || echo false
false
[root@adminset ~]# touch file
[root@adminset ~]# test -f file && echo true || echo false
true

范例6-2 測試字符串(在test命令中使用-z選項(如果測試字符串的長度為0,則表達式成立)

[root@adminset ~]# test -z "luoahong" && ehco 1 || echo 0
0
[root@adminset ~]# char="luoahong"
0
[root@adminset ~]# test -z "$char" && echo 1 || echo 0
0
[root@adminset ~]# char=""
[root@adminset ~]# test -z "$char" && echo 1 || echo 0
1

結論:test命令測試的功能很強大,但是和[] [[]]的功能有所重合,因此,在實際工作中選擇一種適合自己的語法就好了,對於其他的語法,能讀懂別人寫的腳本就可以了

[](中括號)條件測試語法及示例

范例6-3 測試文件(利用[]加-f 選項 文件存在且為普通文件則表達式成立)

[root@adminset ~]# [ -f /tmp/luoahong.txt ] && echo 1 ||echo 0
0
[root@adminset ~]# touch /tmp/luoahong.txt
[root@adminset ~]# [ -f /tmp/luoahong.txt ] && echo 1 ||echo 0
1
[root@adminset ~]# [ -f /tmp/luoahong.txt ] ||echo 0
[root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0
0
[root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0
0
[root@adminset ~]# touch /tmp/luoahong1.txt
[root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0
[root@adminset ~]# rm -f /tmp/luoahong1.txt
[root@adminset ~]# [ -f /tmp/luoahong1.txt ] ||echo 0
0

提示:[]命令的選項和test的命令的選項是通用的,因此,使用[]時的參數選項可以通過man test命令獲的幫助

文件測試表達式

范例6-5:文件屬性條件表達式測試實踐

[root@adminset ~]# ls -l luoahong
-rw-r--r-- 1 root root 0 Jun 14 07:48 luoahong
[root@adminset ~]# [ -r luoahong ] && echo 1 ||echo 0
1
#測試luoahong是否可讀

[root@adminset ~]# [ -w luoahong ] && echo 1 ||echo 0
1
#測試luoahong是否可寫
[root@adminset ~]# [ -x luoahong ] && echo 1 ||echo 0
0
#測試luoahong是否可執行
[root@adminset ~]# chmod 001 luoahong	
[root@adminset ~]# ls -l luoahong
---------x 1 root root 0 Jun 14 07:48 luoahong
#修改后的結果
[root@adminset ~]# [ -w luoahong ] && echo 1 ||echo 0
1
#用戶權限位明明沒有w,為什么還是返回1呢?
[root@adminset ~]# echo 'echo test' >oldboy
#因為確實可以寫啊,這是root用戶比較特殊的地方
[root@adminset ~]# [ -r luoahong ] && echo 1 ||echo 0
1
#用戶權限位明明沒有r,為什么還是返回1呢?
[root@adminset ~]# echo 'echo test' >luoahong
[root@adminset ~]#cat luoahong
echo test
#因為確實可以讀啊,這是root用戶比較特殊的地方。
[root@adminset ~]# [ -x luoahong ] && echo 1 ||echo 0
1
[root@adminset ~]# ./luoahong
[root@adminset ~]# ./luoahong
test

#可執行

提示:測試文件的讀、寫、執行等屬性,不光是根據文件屬性rwx的表示來判斷,

還要看當前執行的用戶是否真的可以按照對應的權限操作該文件

測試shell變量示例

root@adminset ~]# file1=/etc/services;file2=/etc/rc.local
[root@adminset ~]# echo $file1 $file2
/etc/services /etc/rc.local

范例:對單個文件變量進行測試

[root@adminset ~]# [ -f "$file1" ] && echo 1 || echo 0
1
[root@adminset ~]# [ -d "$file1" ] && echo 1 || echo 0
0
[root@adminset ~]# [ -s "$file1" ] && echo 1 || echo 0
1
[root@adminset ~]# [ -e "$file1" ] && echo 1 || echo 0
1
[root@adminset ~]#
[root@adminset ~]#

范例:對單個目錄或文件進行測試

[root@adminset ~]# [ -e /etc ] && echo 1 || echo 0
1
[root@adminset ~]# [ -w /etc/serbices ] && echo 1 || echo 0
0
[root@adminset ~]# su - luoahong
[luoahong@adminset ~]$ [ -w /etc/servies ] && echo 1 || echo 0
0
#文件不可寫,所以返回0

范例:測試變量的特殊寫法及問題

用測試變量時,如果被測試的變量不加雙引號,那么測試結果可能會不時正確的示例如下:

[luoahong@adminset ~]$ echo $tyx
#這是一個不存在的變量,如果讀者已經定義、則可以執行unset取消
[luoahong@adminset ~]$ [ -f $tyx ] && echo 1 || echo 0
1
#命名$tyx變量不存在內容還返回1,邏輯就不對了
[luoahong@adminset ~]$ [ -f "$tyx" ] && echo 1 || echo 0
0
#加了雙引號就返回0,邏輯就對了

如果是文件實體路徑,那么加引號與不加引號的結果時一樣的:

[luoahong@adminset ~]$ [ -f "/etc/services" ] && echo 1 || echo 0
1
[luoahong@adminset ~]$ [ -f /etc/services ] && echo 1 || echo 0
1

范例: 在生產環境下,系統NFS啟動腳本的條件測試

more /etc/init.d/nfs

# Source networking configuration.
[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network

# Check for and source configuration file otherwise set defaults
[ -f /etc/sysconfig/nfs ] && . /etc/sysconfig/nfs

# Remote quota server
[ -z "$RQUOTAD" ] && RQUOTAD=`type -path rpc.rquotad`

特別提示:系統腳本時我們學習編程的第一標桿,新手要多參考腳本來學習,雖然有些腳本也不是特別規范

范例:實現系統bind啟動腳本named

[luoahong@adminset ~]$ [ -r /etc/sysyconfig/network ] && ./etc/sysconfig/network
#若文件存在且可讀,則加載/etc/sysconfig/network
[luoahong@adminset ~]$ [ -x /usr/sbin/$named ] || exit 5

范例:寫出簡單高效的測試文件

在做測試判斷時,不一定非要按照"前面的操作成功了如何,否則如何"的方法來進行。直接做部分判斷,有時看起來更簡潔

[luoahong@adminset ~]$ [ -x luoahong ] && echo 1
#如果luoahong可執行,則輸出1;如果不可執行,則不做任何輸出
[luoahong@adminset ~]$ [ -f /etc ] && echo 1
[luoahong@adminset ~]$ [ -f /etc ] && echo 0
#如果l/etc 是文件這一點不成立,則輸出0,如果成立則不做任何輸出

范例:實現系統腳本/etc/init.d/nfs

[luoahong@adminset ~]$ sed -n '44,50p' /etc/init.d/nfs
# Check that networking is up.
[ "${NETWORKING}" != "yes" ] && exit 6
#如果${NETWORKING}的變量內容不等於yes,則退出

[ -x /usr/sbin/rpc.nfsd ] || exit 5
#如果/usr/sbin/rpc.nfsd的腳本不可執行,則以返回值5退出腳本。如果可執行,則不做任何輸出
[ -x /usr/sbin/rpc.mountd ] || exit 5
[ -x /usr/sbin/exportfs ] || exit 5

特殊表達式測試案例

范例:當條件不成立是,執行大括號里的多條命令,這里要使用邏輯操作符||

[root@adminset 06]# sh 6_15.sh
1
2
3
[root@adminset 06]# cat 6_15.sh
[ -f /etc ] || {
echo 1
echo 2
echo 3

}

[root@adminset 06]# sh 6_15.sh
1
2
3

如果上述腳本寫在一行里面,那么里面的每個命令都需要用分號結尾,示例如下所示:

[root@adminset 06]# [ -f /etc/services ] && { echo "I am luoahong"; echo "I am linuxer"; }

I am luoahong
I am linuxer

提示:本例的兩種用法都很簡潔,但是不如if條件容易理解,因此請讀者根據自身情況選擇使用,更多幫助請man test查詢

字符串測試表達式

字符串測試操作符

范例:字符串條件表達式測試實踐

[root@adminset 06]# [ -n "abc" ] && echo 1 || echo 0
1
[root@adminset 06]# test -n "" && echo 1 || echo 0
0
[root@adminset 06]# var="luoahong"
[root@adminset 06]# [ -n "$var" ] && echo 1 || echo 0
1
[root@adminset 06]# [ -n $var ] && echo 1 || echo 0
1
[root@adminset 06]# var="luoahong1"
[root@adminset 06]# [ -z $var ] && echo 1 || echo 0
0
[root@adminset 06]# [ "abc" = "abd" ] && echo 1 || echo 0
0
[root@adminset 06]# [ "$var" = "luoahong1" ] && echo 1 || echo 0
1
[root@adminset 06]# [ "$var" == "luoahong1" ] && echo 1 || echo 0
1
[root@adminset 06]# [ "$var" != "luoahong1" ] && echo 1 || echo 0
0

字符串測試生產案例

范例:有關雙引號和等號兩端空格的生產系統標准

[root@adminset 06]# sed -n '30,31p' /etc/init.d/network
#check that networking is up
[ "${NETWORKING}" = "no" ] && exit 6
#字符串變量和字符串都加了雙引號,比較符號"="兩端也都有空格

范例:系統腳本/etc/init.d/nfs字符串測試的應用示例

[root@adminset 06]# sed -n '65,80p' /etc/init.d/nfs
[ -z "$MOUNTD_NFS_V2" ] && MOUNTD_NFS_V2=default
#-z的應用,如果變量MOUNTD_NFS_V2的長度為0則賦值default
[ -z "$MOUNTD_NFS_V3" ] && MOUNTD_NFS_V3=default
#-z的應用,如果變量MOUNTD_NFS_V3的長度為0則賦值default
# Number of servers to be started by default
[ -z "$RPCNFSDCOUNT" ] && RPCNFSDCOUNT=8

# Start daemons.
[ -x /usr/sbin/rpc.svcgssd ] && /sbin/service rpcsvcgssd start

# Set the ports lockd should listen on
if [ -n "$LOCKD_TCPPORT" -o -n "$LOCKD_UDPPORT" ]; then #-n的應用
[ -x /sbin/modprobe ] && /sbin/modprobe lockd $LOCKDARG
[ -n "$LOCKD_TCPPORT" ] && \
/sbin/sysctl -w fs.nfs.nlm_tcpport=$LOCKD_TCPPORT >/dev/null 2>&1
[ -n "$LOCKD_UDPPORT" ] && \
/sbin/sysctl -w fs.nfs.nlm_udpport=$LOCKD_UDPPORT >/dev/null 2>&1
fi

整數變量測試示例

范例:通過[]實現整數條件測試

[root@adminset 06]# a1=98;a2=99
[root@adminset 06]# [ $a1 -eq $a2 ] && echo 1 ||echo 0
0
[root@adminset 06]# [ $a1 -gt $a2 ] && echo 1 ||echo 0
0
[root@adminset 06]# [ $a1 -lt $a2 ] && echo 1 ||echo 0
1

范例:利用[[]]和(())實現直接通過常規數學運算符進行比較

[root@adminset 06]# [[ $a1 > $a2 ]] && echo 1 ||echo 0
0
[root@adminset 06]# [[ $a1 < $a2 ]] && echo 1 ||echo 0
1
[root@adminset 06]# (($a1>=$a2)) && echo 1|| echo 0
0
[root@adminset 06]# (($a1<=$a2)) && echo 1|| echo 0
1

范例:系統腳本中使用整數比較的案例

[root@adminset ~]#grep -w "\-eq" /etc/init.d/nfs
[ $RETVAL -eq 0 ] && RETVAL=$rval #過濾出相等(-eq)的例子
[ $RETVAL -eq 0 ] && RETVAL=$rval #使用[],且兩邊都要有一個空格
[ $RETVAL -eq 0 ] && RETVAL=$rval #使用"-eq" 的比較操作符的寫法
[ $RETVAL -eq 0 ] && RETVAL=$rval
[ $RETVAL -eq 0 ] && RETVAL=$rval

[root@adminset ~]#grep -w "\-gt" /etc/init.d/nfs #過濾出大於(-gt)的例子
if [ $cnt -gt 0 ]; then

邏輯操作符實踐示例

范例:[]里的邏輯操作配合文件測試表達式使用的示例

[root@adminset 06]# f1=/etc/rc.local;f2=/etc/services
[root@adminset 06]# echo -ne "$f1 $f2\n"
/etc/rc.local /etc/services
[root@adminset 06]# [ -f "$f1" -a -f "$f2" ] && echo 1 || echo 0
1
[root@adminset 06]# [ -f "$f1" -o -f "$f222" ] && echo 1 || echo 0
1
[root@adminset 06]# [ -f "$f111" -o -f "$f222" ] && echo 1 || echo 0
0
[root@adminset 06]# [ -f "$f1" && -f "$f2" ] && echo 1 || echo 0
-bash: [: missing `]'
0
#這是錯誤的語法,[]中不能用&&||
[root@adminset 06]# [ -f "$f1" ] && [ -f "$f2" ] && echo 1 || echo 0
1
#如果在[]中使用&&,則這樣用

范例:[[]]里邏輯操作符配合字符串的條件表達式的測試示例

[root@adminset 06]# a="luoahong";b="tyx"
[root@adminset 06]# echo -ne "$a $b\n"
luoahong tyx
[root@adminset 06]# [[ ! -n " $a" && "$a" = "$b"]] && echo 1 || echo 0
-bash: conditional binary operator expected
-bash: syntax error near `1'
[root@adminset 06]# [[ ! -n "$a" && "$a" = "$b"]] && echo 1 || echo 0
-bash: conditional binary operator expected
-bash: syntax error near `1'
[root@adminset 06]# [[ ! -n "$a" && "$a" = "$b" ]] && echo 1 || echo 0
0
[root@adminset 06]# [[ -z "$a" || "$a" != "$b" ]] && echo 1 || echo 0
1
[root@adminset 06]#
[root@adminset 06]# [[ -z "$a" -o "$a" != "$b" ]] && echo 1 || echo 0
-bash: syntax error in conditional expression
-bash: syntax error near `-o'

范例:(())里邏輯操作符符合整數的條件表達式測試示例

[root@adminset 06]# m=21;n=38
[root@adminset 06]# ((m>20&&n>30)) && echo 1 || echo 0
1
[root@adminset 06]# ((m>20||n>30)) && echo 1 || echo 0
1
[root@adminset 06]# ((m<20||n<30)) && echo 1 || echo 0
0
[root@adminset 06]# ((m<20 -a n<30)) && echo 1 || echo 0
-bash: ((: m<20 -a n<30: syntax error in expression (error token is "n<30")
0
#內部用-a或-o也會報語法錯誤

范例:使用多個[]號,並通過與或非進行混合測試

[root@adminset 06]# m=21;n=38
[root@adminset 06]# [ $m =gt 20 -a $n -lt 30 ] && echo 1 || echo 0
-bash: [: too many arguments
0
[root@adminset 06]# [ $m gt 20 -a $n -lt 30 ] && echo 1 || echo 0
-bash: [: too many arguments
0
[root@adminset 06]# [ $m -gt 20 -a $n -lt 30 ] && echo 1 || echo 0
0
[root@adminset 06]# [ $m -gt 20 ] || [ $n -lt 30 ] echo 1 || echo 0
[root@adminset 06]# [ $m -gt 20 ] || [ $n -lt 30 ] && echo 1 || echo 0
1

#多個[]號之間用&&或||鏈接

范例:NFS系統啟動腳本中有關[]與或非判斷的使用案例

[root@adminset~]#egrep -wn "\-a|\-o" /etc/init.d/nfs
75:	if [ -n "$LOCKD_TCPPORT" -o -n "$LOCKD_UDPPORT" ]; then
87:	[ "$NFSD_MODULE" != "noload" -a -x /sbin/modprobe ] && {
102:	if [ -n "$RQUOTAD" -a "$RQUOTAD" != "no" ]; then
170:	if [ -n "$RQUOTAD" -a "$RQUOTAD" != "no" ]; then
209:	if [ -n "$RQUOTAD" -a "$RQUOTAD" != "no" ]; then
229:	if [ $MOUNTD = 1 -o $NFSD = 1 ] ; then

范例:系統啟動腳本中有關[[]]的用法和與或非的使用案例

在操作系統中,[[]]的用法不是很多,並且大多數情況都用於通配符匹配的場景,這里不的不通過大海撈針的
方法(遍歷/etc/init.d/下的所有腳本)來幫助大家查找[[]]的用法:

[root@69 ~]# for n in `ls /etc/init.d/*`;do egrep -wn "\[\[ " $n&&echo $n;done
119:	if [[ "$dst" == /dev/mapper* ]] \
/etc/init.d/halt
68:	if [[ $? = 0 ]]; then
/etc/init.d/httpd
641:	if [[ -n "$_target" ]]; then
656:	if [[ "$_rmnt" == "$_mnt" ]] || ! is_dump_target_configured; then
/etc/init.d/kdump
50:	if [[ $route == *" via "* ]] ; then
75:	if ! [[ "$SYSLOGADDR" =~ $IPv4_regex ]] && ! [[ "$SYSLOGADDR" =~ $IPv6_regex ]];then
80:	if [[ $? -eq 2 ]]; then
84:	if [[ $? -ne 0 ]]; then
/etc/init.d/netconsole
167:	if [[ "$rootfs" == nfs* || "$rootopts" =~ _r?netdev ]] ; then
/etc/init.d/network

提示:可見[]中使用-a或-o更常見,[[]]中使用&&或||不常見,使用&&或||鏈接兩個[]的多表達式判斷也不常見

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM