expr命令可以实现数值运算、数值或字符串比较、字符串匹配、字符串提取、字符串长度计算等功能。它还具个特殊功能,判断变量或参数是否为整数、是否为空、是否为0等。
1.字符串表达式
-------------------------
'expr'支持模式匹配和字符串操作。字符串表达式的优先级高于数值表达式和逻辑关系表达式。
'STRING : REGEX'
执行模式匹配。两端参数会转换为字符格式,且第二个参数被视为正则表达式(GNU基本正则),
它默认REGEX中隐含了"^",所以使得匹配时都是从string首字符开始的。随后将第一个参数和正则模式做匹配。
如果匹配成功,且REGEX使用了'\('和'\)',则此表达式返回匹配到的,如果未使用'\('和'\)',则返回匹配的字符数。
如果匹配失败,如果REGEX中使用了'\('和'\)',则此表达式返回空字符串,否则返回为0。
只有第一个'\(...\)'会引用返回的值;其余的'\(...\)'只在正则表达式分组时有意义。
在正则表达式中,'\+','\?'和'\|'分表代表匹配一个或多个,0个或1个以及两端任选其一的意思。
]# expr "ab->cd" : ".*-" #没有\(\),若正则匹配,只返回匹配的字符串长度
3
]# expr "ab->cd" : ".*->" #没有\(\),若正则匹配,只返回匹配的字符串长度
4
]# expr "ab->cd" : ".\+" #没有\(\),若正则匹配,只返回匹配的字符串长度
6
]# expr "ab->cd" : "\(.*\)->\(.*\)" #有多个\(\),若正则匹配,只返回第一个\(\)内容
ab
]# expr "ab->cd" : "\(a.\)"
ab
'match STRING REGEX'
等价于'STRING : REGEX'。
]# expr match "ab->cd" "\(.*b.*\)"
ab->cd
'substr STRING POSITION LENGTH'
返回STRING字符串中从POSITION开始,长度最大为LENGTH的子串。如果POSITION或LENGTH为负数,0或非数值,则返回空字符串。
]# expr substr "ab->cd" 3 2
->
'index STRING CHARSET'
CHARSET中任意单个字符在STRING中最前面的字符位置。如果在STRING中完全不存在CHARSET中的字符,则返回0。见后文示例。
]# expr index "ab->cd" "-"
3
//该命令将对字符串"dec"逐字符分解,首先分解得到第一个字符d,从abcde中搜索到d的位置为4,再分解得到第二个字符e,该字符在abcde中的位置为5,
最后得到的字符是c,该字符在abcde中的位置为3。其中3是最靠前的字符,所以命令返回的结果为3。
]# expr index abcde dec
3
]# expr index abcde 1 //如果chars中的所有字符都不存在于string中,则返回0。
0
'length STRING'
返回STRING的字符长度。其中string不允许为空,否则将报错
]# expr length "ab->cd"
6
'+ TOKEN'
expr中有些符号和关键字有特殊意义,如"match"、"index"、"length",如果要让其成为字符,使用该表达式将任意token强制解析为普通字符串。
]# expr + "substr" : "\(s.*\)"
substr
]# expr length + "substr"
6
要让expr将关键字解析为普通的字符,必须使用引号包围。
2.算术表达式
--------------------------
'expr'支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。
'+ -'
加减运算。两端参数会转换为整数,如果转换失败则报错。
]# expr 3 + 4
7
]# expr 3 - 4
-1
'* / %'
乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。
算术乘法符号"*"因为是shell的元字符,所以要转义,可以使用引号包围,或者使用反斜线
]# expr 4 \* 3
12
]# expr 4 / 3
1
]# expr 4 % 3
1
3.逻辑关系表达式
---------------------------
'expr'支持普通的逻辑连接和逻辑关系。它的优先级最低。
'|'
|需要转义\|,或使用引号包围'|'
正确的应该是:如果第一个参数非0,则返回第一个参数的值,否则返回第二个参数。
但如果任意一个参数为空,则报错。除非空字符串使用引号包围,此时将和0的处理方式一样。
]# expr 1 '|' 2
1
]# expr 1 '|' 0
1
]# expr 0 '|' 1
1
# expr 0 '|' 0
0
]# expr $ab '|' 1 #$ab为空
expr: syntax error
]# expr "$ab" '|' 1 #"$ab"为空字符串,相当于0
1
'&'
&需要转义\&,或使用引号包围'&'
如果两个参数都非0,则返回第一个参数,否则返回0。
但任意一个参数为空,则报错。除非空字符串使用引号包围,此时将和0的处理方式一样。
]# expr 1 '&' 0
0
]# expr 1 '&' 2
1
]# expr 1 '&' 0
0
]# expr 0 '&' 1
0
]# expr $ab '&' 1 #$ab为空,报错
expr: syntax error
]# expr "$ab" '&' 1 #"$ab"为空字符,相当于0
0
'< <= = == != >= >'
比较两端的参数,如果为true,则返回1,否则返回0。"=="是"="的同义词。
"expr"首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。
比较操作符< <= = == != >= >用法示例。其中"<"和">"是正则表达式正的锚定元字符,且"<"会被shell解析为重定向符号,所以需要转义或用引号包围。
这些操作符会首先会将两端的参数转换为数值,如果转换成功,则采用数值比较,如果转换失败,则按照字符集的排序规则进行字符大小比较。
括号'()'可以改变优先级,但使用时需要使用反斜线对括号进行转义。
]# expr 4 '*' 4 - 10 '>=' 6
1
]# expr 4 '*' \( 4 - 10 \) '>=' 6
0
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