1. 程式人生 > >shell指令碼中的各種表示式介紹和使用

shell指令碼中的各種表示式介紹和使用

#前言:在shell指令碼中,有各種的表示式,包括有條件測試表達式,檔案表示式,字串表示式,整數表示式,接下來我們來了解一下他們的使用方法

1.條件測試表達式

#首先來看一下條件測試語法

#條件測試語法                        #說明
1.test <測試表達式>       test命令和後面<內容>之間至少有一個空格
2.[ <測試表達式> ]        單中括號進行條件測試表達式,[]的邊界和內容之間至少要有一個空格
3.[[ <測試表達式> ]]      雙括號,[[]]的邊界和內容也是要有空格
4.((<測試表達式>))        雙小括號,兩端不用空格

#注意點

1、語法1中的test命令和語法2中的[]是等價的。語法3中的[[]]為擴充套件的test命令,語法4中的(())常用於計算

2、在[[]](雙中括號)中可以使用萬用字元等進行模式匹配,這是其區別其他集中語法格式的地方

3、&&、||、>、<等操作符可以應用於[[]]中,但不能應用於[]中,在[]中一般用-a、-o、-gt(用於整數)、-lt(用於整數)代替上述操作符

4、對於整數的關係運算,也可以使用shell的算術運算子(())

 

#詳解

1.1.test條件測試的語法和使用

#檢視幫助:man test

#介紹:test - check file types and compare values(檢查檔案型別和比較值)

#語法格式: test <測試表達式>

#test的幫助文件

[root@shell ~]# man test > 1.txt

[root@shell ~]# cat 1.txt 

TEST(1)                               User Commands                               TEST(1)



NAME
       test - check file types and compare values

SYNOPSIS
       test EXPRESSION
       test

       [ EXPRESSION ]
       [ ]
       [ OPTION

DESCRIPTION
       Exit with the status determined by EXPRESSION.

       --help display this help and exit

       --version
              output version information and exit

       An  omitted  EXPRESSION defaults to false.  Otherwise, EXPRESSION is true or false
       and sets exit status.  It is one of:

       ( EXPRESSION )
              EXPRESSION is true

       ! EXPRESSION
              EXPRESSION is false

       EXPRESSION1 -a EXPRESSION2
              both EXPRESSION1 and EXPRESSION2 are true

       EXPRESSION1 -o EXPRESSION2
              either EXPRESSION1 or EXPRESSION2 is true

       -n STRING
              the length of STRING is nonzero

       STRING equivalent to -n STRING

       -z STRING
              the length of STRING is zero

       STRING1 = STRING2
              the strings are equal

       STRING1 != STRING2
              the strings are not equal

       INTEGER1 -eq INTEGER2
              INTEGER1 is equal to INTEGER2

       INTEGER1 -ge INTEGER2
              INTEGER1 is greater than or equal to INTEGER2

       INTEGER1 -gt INTEGER2
              INTEGER1 is greater than INTEGER2

       INTEGER1 -le INTEGER2
              INTEGER1 is less than or equal to INTEGER2

       INTEGER1 -lt INTEGER2
              INTEGER1 is less than INTEGER2

       INTEGER1 -ne INTEGER2
              INTEGER1 is not equal to INTEGER2

       FILE1 -ef FILE2
              FILE1 and FILE2 have the same device and inode numbers

       FILE1 -nt FILE2
              FILE1 is newer (modification date) than FILE2

       FILE1 -ot FILE2
              FILE1 is older than FILE2

       -b FILE
              FILE exists and is block special

       -c FILE
              FILE exists and is character special

       -d FILE
              FILE exists and is a directory

       -e FILE
              FILE exists

       -f FILE
              FILE exists and is a regular file

       -g FILE
              FILE exists and is set-group-ID

       -G FILE
              FILE exists and is owned by the effective group ID

       -h FILE
              FILE exists and is a symbolic link (same as -L)

       -k FILE
              FILE exists and has its sticky bit set

       -L FILE
              FILE exists and is a symbolic link (same as -h)

       -O FILE
              FILE exists and is owned by the effective user ID

       -p FILE
              FILE exists and is a named pipe

       -r FILE
              FILE exists and read permission is granted

       -s FILE
              FILE exists and has a size greater than zero

       -S FILE
              FILE exists and is a socket

       -t FD  file descriptor FD is opened on a terminal

       -u FILE
              FILE exists and its set-user-ID bit is set

       -w FILE
              FILE exists and write permission is granted

       -x FILE
              FILE exists and execute (or search) permission is granted

       Except for -h and -L, all FILE-related tests dereference symbolic  links.   Beware
       that  parentheses  need  to be escaped (e.g., by backslashes) for shells.  INTEGER
       may also be -l STRING, which evaluates to the length of STRING.

       NOTE: [ honors the --help and --version options, but test does not.   test  treats
       each of those as it treats any other nonempty STRING.

       NOTE:  your  shell may have its own version of test and/or [, which usually super‐
       sedes the version described here.  Please refer to your shell's documentation  for
       details about the options it supports.

       GNU  coreutils  online  help: <http://www.gnu.org/software/coreutils/> Report test
       translation bugs to <http://translationproject.org/team/>

AUTHOR
       Written by Kevin Braunsdorf and Matthew Bradburn.

COPYRIGHT
       Copyright © 2013 Free Software Foundation, Inc.  License GPLv3+: GNU GPL version 3
       or later <http://gnu.org/licenses/gpl.html>.
       This  is  free  software: you are free to change and redistribute it.  There is NO
       WARRANTY, to the extent permitted by law.

SEE ALSO
       The full documentation for test is maintained as a Texinfo manual.   If  the  info
       and test programs are properly installed at your site, the command

              info coreutils 'test invocation'

       should give you access to the complete manual.



GNU coreutils 8.22                     August 2019                                TEST(1)
View Code

#使用

#例一:判斷如果file檔案存在且為一個檔案,就輸出true,否則輸出false

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

#講解:因為file這個檔案不存在,所以輸出false,&&是並且的意思,||表示前面一個執行失敗才會執行後面

 

#例二:使用-z選項(如果測試字串的長度為0,則表示式成立)

[root@shell ~]# test -z "guoke" && echo 1 || echo 0
0  #因為測試的字串為guoke,不為空值,所以為假輸出0
[root@shell ~]# char="guoke"
[root@shell ~]# test -z "$char" && echo 1 || echo 0
0  #因為guoke賦值給了char,所以也不是空值,輸出0
[root@shell ~]# char=""
[root@shell ~]# test -z "$char" && echo 1 || echo 0
1  #char為空值,所以長度為0,表示式成立輸出1

 

1.2.[]中括號條件測試語法和使用

#語法格式:[ <測試表達式> ]

#注意點:中括號內部的兩端都要有空格,[]和test用法一樣,test的判斷選項也可以在[]中用

#輸入兩端都有空格的技巧:先輸入一對中括號,然後退一個格,輸入兩個空格,再退一個格

#例子:利用[]加-f選項(如果檔案存在且為普通檔案則表示式就成立)

[root@shell ~]# [ -f /tmp/guoke.txt ] && echo 1 || echo 0
0  #檔案不存在所以輸出0
[root@shell ~]# touch /tmp/guoke.txt
[root@shell ~]# [ -f /tmp/guoke.txt ] && echo 1 || echo 0
1  #檔案存在且為一個普通檔案,則輸出1
[root@shell ~]# [ -f /tmp/guoke.txt ] && echo 1
1

 

1.3.[[]] 雙中括號條件測試語法及使用

#語法格式:[[ <測試表達式> ]]

#注意點:雙中括號的兩端需要有空格

#例子:判斷檔案存在且為一個普通檔案

[root@shell ~]# [[ -f /tmp/test.txt ]] && echo 1 || echo 0
0  #檔案不存在所以條件不成立,輸出0
[root@shell ~]# touch /tmp/test.txt
[root@shell ~]# [[ -f /tmp/test.txt ]] && echo 1 || echo 0
1  #檔案存在且為普通檔案,條件成立,輸出1
[root@shell ~]# [[ -f /tmp/test.txt ]] && echo 1
1

 

1.4.特殊條件測試表達式例子

#判斷條件測試表達式的條件成立或不成立後,還需要執行多條命令語句的語法,不用if測試表達式的格式

#當條件1成立時,同時執行多條命令

test 條件1 && {

}

[ 條件1 ] && {
    命令1
    命令2  

}
[[ 條件1 ]] && {

}

#例子:當條件成立的時候就執行後面的命令

[root@shell ~]# cat test.sh 
#!/bin/bash
[ $1 -eq 3 ] && {
    echo 1
    echo 2
    echo 3
}

[root@shell ~]# sh test.sh 3 #傳參
1
2
3

#上面的判斷相當於下面if語句的效果

if [ 條件1 ];then
    命令1
    命令2
fi

 

#關於條件測試表達式的總結

#1.test和[]、[[]]的功能有所重合,因此在工作中選擇一種適合自己的一種用,其他的可以看懂別人的寫的指令碼就好了,可以同man test檢視更多引數用法

#2.測試表達式test、[]、[[]]、(())區別總結

測試表達式符號            test             []             [[]]          (())
邊界是否需要空格          需要              需要            需要         不需要
邏輯操作符              !、-a、-o        !、-a、-o       !、&&、||     !、&&、||
整數比較操作符            -eq -gt -lt -ge -le(test,[],[[]])          = < > >= <=
字串比較操作符           =、==、!= (全部支援)
是否支援萬用字元匹配        不支援          不支援            支援         不支援

 

2.檔案表示式

#常用的檔案測試操作符

#常用操作符                        #說明
-f 檔案,全稱file            #檔案存在且為普通檔案則為真,表示式成立
-d 檔案,全稱directory       #檔案存在且為目錄則為真,表示式成立
-s 檔案,全稱size            #檔案存在且大小不為0為真
-e 檔案,全稱exist           #檔案存在則為真
-r 檔案,全稱read            #檔案存在且為可讀則為真,表示式成立
-w 檔案,全稱write           #檔案存在且可寫為真,表示式成立
-x 檔案,全稱executable      #檔案存在且可執行為真
-L 檔案,全稱link            #檔案存在且為連結檔案為真
f1 -nt f2,英文newer than    #檔案f1比檔案f2新則為真,根據檔案修改時間計算
f1 -ot f2,英文older than    #檔案f1比檔案f2舊為真,根據修改時間計算

 #提示:這些操作符對於test,[],[[]]幾乎是通用的,可以使用man test檢視更多的操作符

#例子:

 #1.-f,判斷檔案是否存在且為普通檔案

[root@shell ~]# touch test
[root@shell ~]# ls -l test
-rw-r--r-- 1 root root 0 Mar 18 16:02 test
[root@shell ~]# [ -f test ] && echo 1 || echo 0
1   #解析:因為檔案存在且為普通檔案,所以為真輸出1

 

#2.-d,判斷檔案是否存在且為目錄

[root@shell ~]# mkdir test1
[root@shell ~]# [ -d test1 ] && echo 1 || echo 0
1  #因為檔案存在且為目錄,所以為真輸出1,如果不存在就輸出0

 

#3.測試檔案屬性:r,w,x

[root@shell ~]# ls -ld test
-rw-r--r-- 1 root root 0 Mar 18 16:02 test
[root@shell ~]# [ -r test ] && echo 1 || echo 0
1   #檔案存在且可讀,為真,輸出1
[root@shell ~]# [ -w test ] && echo 1 || echo 0
1   #檔案存在且可寫,為真,輸出1
[root@shell ~]# [ -x test ] && echo 1 || echo 0
0  #檔案不可執行,不為真,所以輸出0
[root@shell ~]# chmod +x test
[root@shell ~]# [ -x test ] && echo 1 || echo 0
1   #加了可執行許可權就為真成立了

#提示:測試檔案的讀、寫、執行等屬性,不光是根據檔案屬性rwx的標識來判斷,還要看當前執行測試的使用者是否真的可以按照對應的許可權操作該檔案

 

#測試時變數的特殊寫法及問題

#用[]測試變數時,如果被測試的變數不加雙引號,那麼測試結果可能會是不正確的

#例子

[root@shell ~]# echo $test  #不存在的變數

[root@shell ~]# [ -f $test ] && echo 1 || echo 0 #不加引號返回的結果時錯誤的
1
[root@shell ~]# [ -f "$test" ] && echo 1 || echo 0 #新增以後返回的結果是正確的
0 

 

#注意點:做測試判斷時,不一定非要按照前面的如果成立了輸出什麼,不成立輸出什麼,可以直接做部分判斷

[root@shell ~]# [ -x test ] && echo 1  #如果test檔案可執行,就輸出1,否則不做任何輸出
[root@shell ~]# [ -f /etc ] || echo 0  #如果前面執行失敗就輸出0,否則不做任何輸出
0

 

3.字串表示式

#字串表示式作用:比較兩個字串是否相同、測試字串的長度是否為0、字串是否為null等

#常用的字串測試操作符

#常用字串操作符                #說明
-z "字串"                    如果字串長度為0則為真,
-n "字串"                    如果字串長度不為0則為真,
"字串1" = "字串2"           如果字串1等於字串2則為真,可以使用==代替=
"字串1" != "字串2"          如果字串1不等於字串2則為真,不能使用!==代替!=

 #提示:

#1.上面的字串測試操作符必須要有""引起來

#2.比較符號兩端要有空格

#3.-n 比較字串長度是否不為0,如果不為0則為真,用法 [ -n "$my" ]

#4.-z 比較字串長度是否為0,如果為0則為真,用法 [ -z "$my" ]

 #例1:-n,-z引數應用

[root@shell ~]# [ -n "abc" ] && echo 1 || echo 0
1    #-n是不為空則為真,字串長度為abc,所以長度不是為0,為真輸出1
[root@shell ~]# test -n "aa" && echo 1 || echo 0
1    
[root@shell ~]# test -n "" && echo 1 || echo 0
0    #字串為空,不為真,數以輸出0
[root@shell ~]# var="test"
[root@shell ~]# [ -n "$var" ] && echo 1|| echo 0
1
[root@shell ~]# [ -z "$var" ] && echo 1|| echo 0
0    #-z是為空值為真,不為空值為假,所以輸出0,
[root@shell ~]# [ "aa" = "aa" ] && echo 1 || echo 0
1    #字串相等,所以長度為0,為真

 

#例二:進行字串比較時,如果等號兩端沒有空格帶來的問題

[root@shell ~]# [ "abc"="1" ]&& echo 1 || echo 0 
1     #等號兩邊沒有空格,明顯是不成立的也輸出了1
[root@shell ~]# [ "abc" = "1" ]&& echo 1 || echo 0 
0    #正常現象

 

#總結:字串比較時若等號兩端沒有空格,則會導致判斷出現邏輯錯誤,即使語句沒有問題,但是結果依然可能不對

 

#例三:字串不加引號可能帶來的問題

[root@shell ~]# var=""    #將變數內容設定為空
[root@shell ~]# [ -n "$var" ] && echo 1 || echo 0
0    #-n是值不為空則為真,因為變數內容為0,為空值,所以不為真,輸出0
[root@shell ~]# [ -n $var ] && echo 1 || echo 0
1    #不加雙引號導致返回結果錯誤
[root@shell ~]# [ -z "$var" ]&& echo 1 || echo 0
1    #-z是字串長度為0,則為真

 

#檢視有關雙引號和等號兩端空格的生產系統標準

[root@shell ~]# sed -n '30,31p' /etc/init.d/network 
# Check that networking is up.
[ "${NETWORKING}" = "no" ] && exit 6

 

4.整數表示式

#整數二元比較操作符

在test及[]中使用的比較符號    在[[]]和(())中使用的比較符號        說明
-eq                            == 或 =                 相等,全稱equal
-ne                              !=                   不相等,全稱not qeual
-gt                               >                   大於,全稱greater than
-ge                               >=                  大於等於,全稱為greater equal
-lt                               <                   小於,全稱less than
-le                               <=                  小於等於,全稱less equal                              

 #提示:如果選擇整數比較的時候,要確保兩邊是整數,如[ 2 -eq 1 ]

 #注意:"<"和">"在[]中括號裡面需要轉義,對於數字不轉義的結果可能不會報錯,但是結果可能不對,=和!=在[]不用轉義

#例子

[root@shell ~]# [ 2 > 3 ] && echo 1 || echo 0
1 #結果應該返回0,但是不轉義返回了1是錯誤的
[root@shell ~]# [ 2 \> 3 ] && echo 1 || echo 0
0 #進行轉義之後輸出正確
[root@shell ~]# [ 2 < 1 ] && echo 1 || echo 0
1
[root@shell ~]# [ 2 \< 1 ] && echo 1 || echo 0
0

 

 #整數比較的推薦用法,使用-eq,-lt,-gt

#例子

[root@shell ~]# [ 13 -lt 24 ] && echo 1
1  #13小於24結果為真就輸出1

 

5.邏輯操作符

#常用的邏輯操作符

在test及[]中使用的比較符號    在[[]]和(())中使用的比較符號        說明
    -a                              &&                     and,且,兩端都為真,則結果為真
    -o                              ||                     or,或,兩端有一個為真,則結果為真
     !                               !                     not,非,兩端相反,則結果為真

#提示

1、邏輯操作符前後的表示式是否成立,一般用真假來表示
2、“!”的中文意思是反,即與一個邏輯值相反的邏輯值
3、-a的中文意思是“與”(and或&&),前後兩個邏輯值都為“真”,綜合返回值才為真,否則為假
4、-o的中文意思是“或”(or或||),前後兩個邏輯值只要有一個為真,返回值就為真
5、連線兩行[]、test或[[]]的表示式可用&&或||

 #提示:中括號裡面不能使用&&字串,否則報錯,在[[]]和(())裡面就可以用,可參考上面列出的

[root@shell ~]# [ -f "$f1" && -f "$f2" ] && echo 1 || echo 0
-bash: [: missing `]'
0

 

#例一:

[root@shell ~]# f1=/etc/rc.local
[root@shell ~]# f2=/etc/services
[root@shell ~]# [ -f "$f1" -a -f "$f2" ] && echo 1 || echo 0
1  #判斷如果f2和f2變數的檔案存在且為檔案的話,就為真,輸出1,如果一個不為真,那麼久不為真,就輸出0
[root@shell ~]# [[ -f "$f1" && -f "$f2" ]] && echo 1 || echo 0 
1  #在[[]]雙中括號中就可以使用&&
[root@shell ~]# [ -f "$f1" ]&&[ -f "$f2" ] && echo 1 || echo 0
1  #或者在兩個[]之間使用&&也可以

 

 #例二:

[root@shell ~]# a=1
[root@shell ~]# b=2
[root@shell ~]# [ "$a" -eq 2 -a "$b" -eq 2 ] && echo 1 || echo 0
0    #如果變數a等於2且變數b也等於2,則為真,否則為假,輸出0
[root@shell ~]# [ "$a" -eq 1 -a "$b" -eq 2 ] && echo 1 || echo 0
1
[root@shell ~]# [ "$a" -eq 1 -o "$b" -eq 2 ] && echo 1 || echo 0
1    #如果變數a等於或變數b等於2,則為真,輸出1,-o是或,有一個條件成立則為真    
[root@shell ~]# [ "$a" -eq 2 -o "$b" -eq 3 ] && echo 1 || echo 0
0

&n