使用expr轻松实现数值与字符串运算

在Linux世界中,expr命令是一个强大的工具,它可以进行数值和字符串的运算操作。无论你是系统管理员还是脚本编写者,掌握expr命令都能让你的工作更加高效。今天,我们就来深入了解一下expr命令的奥秘。

一、命令简介

expr,全称为expression,在Linux系统中作为一款基础的表达式计算工具,主要用于进行整数的算术运算、字符串长度计算以及进行简单的字符串比较等操作。尽管在现代Shell脚本编写中,许多功能已被更为高级的构造如$(( ))或let命令所替代,但expr命令因其兼容性和便利性,仍广泛应用于各种Shell脚本场景。

二、命令用法

expr命令的基本语法如下:


expr Expression

其中,表达式Expression可以是一个算术表达式、比较表达式或字符串表达式。expr命令会对表达式进行求值,并输出结果。

Expression应遵循以下规则:

  • 用空格隔开每个项。
  • 用\(反斜线)对Shell特殊字符进行转义。
  • 对包含空格和其它特殊字符的字符串要用引号括起来。

所有命令都可以放在一对反引号“中,或者是使用命令替换$(),以获取expr的结果并赋值给变量,从而进行其它处理。例如,计算两个整数之和,可以这样使用:


result=$(expr 5 + 2)
result=$(expr $result + 1)

三、日常使用示例

1、数值运算

expr命令支持基本的算术运算,包括加法、减法、乘法、除法和取模。例如:


$ expr 5 + 3   # 输出:8
$ expr 5 \* 3  # 输出:15
$ expr 5 % 3   # 输出:2

注意:乘法操作符(*)需要进行转义,否则会被解释为通配符。

2、比较操作

expr命令还支持比较操作,用于比较两个数值或字符串的大小。例如:


$ expr 5 \>= 5         # 输出:1(表示真)
$ expr 5 \< 5          # 输出:0(表示假)
$ expr foo \> bar      # 输出:1(表示真)
$ expr hello != world  # 输出:1(表示真)
$ expr hello = hello   # 输出:1(表示真)

注意:比较操作符中的大于(>)、小于(<)需要进行转义,否则会被解释为Shell的重定向操作符。

3、字符串操作

expr命令还可以进行字符串操作,如长度计算、子串匹配等。例如:


$ expr length hello        # 输出:5(字符串长度)
$ expr index hello e       # 输出:2(子串在字符串中的位置)
$ expr substr hello 2 3    # 输出:ell(从第2个字符开始取3个字符的子串)
$ expr abc123 : "[a-z]*[0-9]*"      # 输出:6(模式匹配到的文本长度)
$ expr abc123 : "[a-z]*\([0-9]*\)"  # 输出:123(捕获模式匹配到的文本)
# expr ARG1 : AGR2 也可以写成 expr match ARG1 AGR2

注意:这里的正则表达式并未完全按照POSIX扩展正则标准,expr中的正则表达式功能相对有限。使用圆括号用于捕获文本,需要对圆括号进行转义(\(..\)),如果有多组括号,只会输出第一个捕获组的内容。

在Bash脚本编写中,我们更倾向于使用grep、sed或者Shell的内建 ${#variable}、${variable:offset:length}、${variable#prefix} 和 ${variable%suffix} 等方式进行字符串操作,因为它们的功能更为强大且易于使用。但对于一些旧版系统或特定场景下,expr仍然是一个可用的选择。

4、逻辑运算

expr命令还可以进行逻辑操作:


$ expr ARG1 \| ARG2  # 若ARG1的值不为null或0,则返回ARG1,否则返回ARG2
$ expr 0 \| 5        # 输出:5
$ expr ARG1 \& ARG2  # 若两边的值都不为null或0,则返回ARG1,否则返回0
$ expr 2 \& 5        # 输出:2

注意:或操作符(|)、与操作符(&)需要进行转义。否则,前者会被解释为Shell的管道符,后者会被解释为命令分隔符,它前面的部分作为一个命令将在后台运行,后面的部分作为另一个命令运行。

需要注意的是,expr命令中运算符两边的操作数如果包含空格或者可能是空字符串,空格前必须加上转义字符(\),或者将操作数放在引号中。这是因为空格在Shell中有特殊意义(被当成参数分隔符),而空字符串通常不会被Shell传递给命令,在这种情况下命令会显示错误信息:expr: syntax error。这一点适用很多场景,但在Bash中使用双中括号([[ ]])时,不用考虑这些情况。例如,以下两种方式都可以比较两个变量是否相等:


expr "$a" = "$b"
[[ $a = $b ]]

当其中一个或两个参数为空、或者包含空格时,命令都能正确执行。

四、为什么要使用expr

相对于Bash等Shell中的高级用法,expr有其独特的兼容性和便利性。例如,要计算一段文本的长度,常规做法:


$ var='This is a paragraph of text'
$ echo ${#var}
# 输出:27

或者:


$ printf 'This is a paragraph of text'|wc -c
# 输出:27

使用expr直接计算这段文本的长度:


$ expr length 'This is a paragraph of text'
# 输出:27

再看另一个使用场景,在函数中返回计算结果,以计算两个时间之间相差的秒数为例(时间格式为:yyyy-mm-dd HH:MM:SS):


function time_diff() {
  local t1=$(date -d "$1" +%s)
  local t2=$(date -d "$2" +%s)
  diff=$[t1-t2]
  echo $diff
}

如果使用expr,函数可以写成这样:


function time_diff() {
  local t1=$(date -d "$1" +%s)
  local t2=$(date -d "$2" +%s)
  expr $t1 - $t2
}

这样看起来更直观。

总结

理解并熟练运用expr命令,将让你的Linux命令行操作更加得心应手,也会提升数据处理和脚本编程的能力。