expr命令可以實現數值運算、數值或字符串比較、字符串匹配、字符串提取、字符串長度計算等功能。它還具有幾個特殊功能,判斷變量或參數是否為整數、是否為空、是否為0等。
1.expr中文手冊(info expr)
先看expr命令的info文檔 info expr 的翻譯。
16.4.1 字符串表達式 ------------------------- 'expr'支持模式匹配和字符串操作。字符串表達式的優先級高於數值表達式和邏輯關系表達式。 'STRING : REGEX' 執行模式匹配。兩端參數會轉換為字符格式,且第二個參數被視為正則表達式(GNU基本正則),它默認會隱含前綴"^"。隨后將第一個參數和正則模式做匹配。 如果匹配成功,且REGEX使用了'\('和'\)',則此表達式返回匹配到的,如果未使用'\('和'\)',則返回匹配的字符數。 如果匹配失敗,如果REGEX中使用了'\('和'\)',則此表達式返回空字符串,否則返回為0。 只有第一個'\(...\)'會引用返回的值;其余的'\(...\)'只在正則表達式分組時有意義。 在正則表達式中,'\+','\?'和'\|'分表代表匹配一個或多個,0個或1個以及兩端任選其一的意思。 'match STRING REGEX' 等價於'STRING : REGEX'。 'substr STRING POSITION LENGTH' 返回STRING字符串中從POSITION開始,長度最大為LENGTH的子串。如果POSITION或LENGTH為負數,0或非數值,則返回空字符串。 'index STRING CHARSET' CHARSET中任意單個字符在STRING中最前面的字符位置。如果在STRING中完全不存在CHARSET中的字符,則返回0。見后文示例。 'length STRING' 返回STRING的字符長度。 '+ TOKEN' 將TOKEN解析為普通字符串,即使TOKEN是像MATCH或操作符"/"一樣的關鍵字。這使得'expr length + "$x"'或'expr + "$x" : '.*/\(.\)''可以正常被測試,即使"$x"的值可能是'/'或'index'關鍵字。這個操作符是一個GUN擴展。 通用可移植版的應該使用'" $token" : ' \(.*\)''來代替'+ "$token"'。 要讓expr將關鍵字解析為普通的字符,必須使用引號包圍。 16.4.2 算術表達式 -------------------------- 'expr'支持普通的算術操作,算術表達式優先級低於字符串表達式,高於邏輯關系表達式。 '+ -' 加減運算。兩端參數會轉換為整數,如果轉換失敗則報錯。 '* / %' 乘,除,取模運算。兩端參數會轉換為整數,如果轉換失敗則報錯。 16.4.3 邏輯關系表達式 --------------------------- 'expr'支持普通的邏輯連接和邏輯關系。它的優先級最低。 '|' 如果第一個參數非空且非0,則返回第一個參數的值,否則返回第二個參數的值,但要求第二個參數的值也是非空或非0,否則返回0。如果第一個參數是非空或非0時,不會計算第二個參數。 經過測試,以上手冊內容是錯誤的。正確的應該是:如果第一個參數非0,則返回第一個參數的值,否則返回第二個參數。但如果任意一個參數為空,則報錯。除非空字符串使用引號包圍,此時將和0的處理方式一樣。 '&' 如果兩個參數都非空且非0,則返回第一個參數,否則返回0。如果第一個參為0或為空,則不會計算第二個參數。 經過測試,以上手冊內容是錯誤的。正確的應該是:如果兩個參數都非0,則返回第一個參數,否則返回0。但任意一個參數為空,則報錯。除非空字符串使用引號包圍,此時將和0的處理方式一樣。 '< <= = == != >= >' 比較兩端的參數,如果為true,則返回1,否則返回0。"=="是"="的同義詞。"expr"首先嘗試將兩端參數轉換為整數,並做算術比較,如果轉換失敗,則按字符集排序規則做字符比較。 括號'()'可以改變優先級,但使用時需要使用反斜線對括號進行轉義。 16.4.4 'expr'使用示例 ------------------------------- 以下為expr的一些示例,其中有將shell的元字符使用引號包圍的示例。 將shell中變量'foo'的值增加1: foo=$(expr $foo + 1) 輸出變量路徑變量'$fname'中不包含'/'的文件名部分: expr $fname : '.*/\(.*\)' '|' $fname 解釋:其中的'|'是expr中的連接符,只不過是被引號包圍防止被shell解析。例如$fname=/etc/hosts,則此表達式返回hosts,如果$fname=/usr/share/,則此表達式'|'的左邊為空,所以返回'|'右邊的值,即$fname,即返回/usr/share/。 An example showing that '\+' is an operator: expr aaa : 'a\+' # 解釋:因為REGEX部分沒有使用\(\),所以返回匹配的字符數 => 3 expr abc : 'a\(.\)c' # 解釋:因為REGEX部分使用了\(\),所以返回匹配的字符 => b expr index abcdef cz => 3 expr index index a # 解釋:因為第二個index是關鍵字 error-> expr: syntax error expr index + index a # 解釋:使用+將index關鍵字解析為普通字符串 => 0
expr使用示例
下面將使用示例來介紹expr的用法,在介紹之前,需要注意三點:
(1).數值表達式("+ - * / %")和比較表達式("< <= = == != >= >")會先將兩端的參數轉換為數值,轉換失敗將報錯。所以可借此來判斷參數或變量是否為整數。 (2).expr中的很多符號需要轉義或使用引號包圍。 (3).所有操作符的兩邊,都需要有空格。
以下是expr示例。
(1)."string : REGEX"字符串匹配示例。要輸出匹配到的字符串結果,需要使用"\("和"\)",否則返回的將是匹配到的字符串數量。
[root@localhost ~]# expr abcde : 'ab\(.*\)' cde [root@localhost ~]# expr abcde : "ab\(.*\)" cde [root@localhost ~]# expr abcde : 'ab\(.\)' c [root@localhost ~]# expr abcde : 'ab.*' 5 [root@localhost ~]# expr abcde : 'ab.' 3 [root@localhost ~]# expr abcde : '.*cd*' 4
注意,由於REGEX中隱含了"^",所以使得匹配時都是從string首字符開始的。
[root@localhost ~]# expr abcde : 'cd.*' 0
之所以為0,是因為真正的正則表達式是"^cd.*",而abcde不是c開頭而是a開頭的,所以無法匹配到任何結果。因此,任何字符串匹配時,都應該從首字符開始。
字符串匹配時,會先將兩端參數轉換為字符格式。
(2)."index string chars"用法示例。
該表達式是從string中搜索chars中某個字符的位置,這個字符是string中最靠前的字符。例如:
[root@localhost ~]# expr index abcde dec 3
該命令將對字符串"dec"逐字符分解,首先分解得到第一個字符d,從abcde中搜索到d的位置為4,再分解得到第二個字符e,該字符在abcde中的位置為5,最后得到的字符是c,該字符在abcde中的位置為3。其中3是最靠前的字符,所以命令返回的結果為3。
[root@localhost ~]# expr index abcde xdc 3
如果chars中的所有字符都不存在於string中,則返回0。
[root@localhost ~]# expr index abcde 1 0 [root@localhost ~]# expr index abcde 1x 0 [root@localhost ~]# expr index abcde x 0
(3)."substr string pos len"用法示例。
該表達式是從string中取出從pos位置開始長度為len的子字符串。如果pos或len為非正整數時,將返回空字符串。
[root@localhost ~]# expr substr abcde 2 3 bcd [root@localhost ~]# expr substr abcde 2 4 bcde [root@localhost ~]# expr substr abcde 2 0 [root@localhost ~]# expr substr abcde 2 -1 [root@localhost ~]#
(4)."length string"用法示例。該表達式是返回string的長度,其中string不允許為空,否則將報錯,所以可以用來判斷變量是否為空。
[root@localhost ~]# expr length abcde 5 [root@localhost ~]# expr length 111 3 [root@localhost ~]# expr length $xxx expr: 語法錯誤 [root@localhost ~]# if [ $? -ne 0 ];then echo '$xxx is null';fi $xxx is null
(5)."+ token"用法示例。
expr中有些符號和關鍵字有特殊意義,如"match"、"index"、"length",如果要讓其成為字符,使用該表達式將任意token強制解析為普通字符串。
[root@localhost ~]# expr index index d expr: 語法錯誤 [root@localhost ~]# expr index length g expr: 語法錯誤 [root@localhost ~]# expr index + length g 4
對值為關鍵字的變量來說,則無所謂。
[root@localhost ~]# len=lenght [root@localhost ~]# expr index $len g 4
(6).算術運算用法示例。
[root@localhost ~]# expr 1 + 2 3 [root@localhost ~]# a=3 [root@localhost ~]# b=6 [root@localhost ~]# expr $a + $b 9 [root@localhost ~]# expr 4 + $a 7 [root@localhost ~]# expr $a - $b -3
算術乘法符號"*"因為是shell的元字符,所以要轉義,可以使用引號包圍,或者使用反斜線。
[root@localhost ~]# expr $a * $b expr: 語法錯誤 [root@localhost ~]# expr $a '*' $b 18 [root@localhost ~]# expr $a \* $b 18 [root@localhost ~]# expr $b / $a 2 [root@localhost ~]# expr $b % $a 0
[root@localhost ~]# expr 1 + a
expr: 參數數目錯誤
任意操作符兩端都需要有空格,否則:
[root@localhost ~]# expr 4+$a 4+3 [root@localhost ~]# expr 4 +$a expr: 語法錯誤
(7).比較操作符< <= = == != >= >用法示例。其中"<"和">"是正則表達式正的錨定元字符,且"<"會被shell解析為重定向符號,所以需要轉義或用引號包圍。
這些操作符會首先會將兩端的參數轉換為數值,如果轉換成功,則采用數值比較,如果轉換失敗,則按照字符集的排序規則進行字符大小比較。比較的結果若為true,則expr返回1,否則返回0。
[root@localhost ~]# a=3 [root@localhost ~]# expr $a = 1 0 [root@localhost ~]# expr $a = 3 1 [root@localhost ~]# expr $a \* 3 = 9 1 [root@localhost ~]# expr abc \> ab 1 [root@localhost ~]# expr akc \> ackd 1 [root@localhost ~]#
(8).邏輯連接符號"&"和"|"用法示例。這兩個符號都需要轉義,或使用引號包圍。
"&"表示如果兩個參數都非0,則返回第一個參數,否則返回0。但任意一個參數為空,則expr報錯。除非空字符串使用引號包圍,則處理方法和0一樣。
"|"表示如果第一個參數非0,則返回第一個參數的值,否則返回第二個參數。但如果任意一個參數為空,則expr報錯。除非空字符串使用引號包圍,則處理方法和0一樣。
[root@localhost ~]# expr $abc '|' 1 expr: 語法錯誤 [root@localhost ~]# expr "$abc" '|' 1 1 [root@localhost ~]# expr "$abc" '&' 1 0 [root@localhost ~]# expr $abc '&' 1 expr: 語法錯誤 [root@localhost ~]# expr 0 '&' abc 0 [root@localhost ~]# expr abc '&' 0 0 [root@localhost ~]# expr abc '|' 0 abc [root@localhost ~]# expr 0 '|' abc abc [root@localhost ~]# expr abc '&' cde abc [root@localhost ~]# expr abc '|' cde abc