9.Shell脚本修炼手册---数值计算实践
Shell 数值计算实践
文章目录
- Shell 数值计算实践
- 算术运算符
- $(()) 双小括号数值运算命令
- $(()) 双小括号数值运算的基础语法
- $(()) 双小括号运算实践
- let 命令
- expr 命令
- expr 命令的基本用法
- expr 的企业级实战案例
- bc 命令
- awk 命令实现计算
- $[] 符号的运算
算术运算符
在 Shell 中进行数值计算时,我们需要用到各种算术运算符。这些运算符和我们平时接触的数学运算符号很相似,只是在 Shell 中有特定的使用规则。下面为大家详细介绍常见的 Shell 算术运算符:
- +、-(一元):表示正数或负数,比如
+5
表示正 5,-3
表示负 3。 - +、-(二元):表示加法和减法,比如
2+3
结果为 5,5-2
结果为 3。 - *、/、%:分别表示乘法、除法、取余(取模)。例如
2*3=6
,6/2=3
,7%3=1
(7 除以 3 的余数是 1)。 - **:表示幂运算,比如
2**3
表示 2 的 3 次方,结果为 8。 - ++、–:自增和自减运算符,既可以放在变量前面(如
++a
),也可以放在变量后面(如a++
)。前置时先运算再使用变量值,后置时先使用变量值再运算。 - !、&&、||:逻辑运算符,分别表示逻辑非(取反)、逻辑与(and)、逻辑或(or)。比如
!true
结果为假,true && false
结果为假,true || false
结果为真。 - <、<=、>、>=:比较运算符,分别表示小于、小于等于、大于、大于等于。比如
3<5
结果为真,5>=6
结果为假。 - ==、!=、=:比较运算符,
==
和=
表示相等(字符串比较时也可用=
),!=
表示不相等。比如3==3
结果为真,4!=5
结果为真。 - <<、>>:移位运算符,
<<
表示向左移位,>>
表示向右移位(二进制层面的操作)。比如8<<1
(8 的二进制是 1000,左移 1 位变为 10000,即 16)。 - ~、|、&、^:按位运算符,
~
是按位取反,|
是按位或,&
是按位与,^
是按位异或(针对二进制位的运算)。 - =、+=、-=、*=、/=、%=:赋值运算符,
a=5
表示给 a 赋值 5;a+=1
等价于a=a+1
,即 a 的值加 1 后重新赋值给 a;其他运算符类似。
在 Shell 中,常用的算术运算命令有以下几种,它们各自有不同的特点和适用场景:
- $(()):专门用于整数运算,效率高,用法灵活,是运维人员常用的运算方式。
- let:功能和
$(())
类似,也用于整数运算。 - expr:可用于整数运算,还能处理字符串长度、匹配等操作。
- bc:Linux 自带的计算器程序,支持整数和小数运算。
- $[]:用于整数运算,语法简单。
- awk:既能处理整数运算,也能处理小数运算,精度较高。
- declare:通过
-i
参数定义整数变量,之后可直接对变量进行运算。
$(()) 双小括号数值运算命令
双小括号 $(())
是 Shell 中进行数值运算和数值比较的高效工具,用法灵活,在实际工作中经常被使用。
$(()) 双小括号数值运算的基础语法
$(())
的使用方式主要有以下几种:
- ((变量 = 表达式)):先计算表达式,再将结果赋值给变量。例如
((i=i+1))
表示将 i+1 的结果重新赋值给 i。 ⚠️ 注意:不能直接用echo ((i=i+1))
输出结果,需要用echo $((i=i+1))
才能输出运算后的值。 - ** 变量 =(((表达式))**:在
\)(())
前加\(
,表示将表达式的运算结果赋值给变量。例如i=\)((i+1))
和上面的((i=i+1))
效果相同。 - ((比较表达式)):可进行比较操作,还能结合逻辑与(
&&
)、逻辑或(||
)用于条件判断。例如((8>7 && 5==5))
表示判断 8 大于 7 且 5 等于 5,结果为真。 - echo $((表达式)):直接输出表达式的运算结果。例如
echo $((2+1))\
会输出 3。
$(()) 双小括号运算实践
实验流程:通过多个示例演示 $(())
的基本用法,包括简单计算、复杂计算、特殊运算符使用、比较判断、自增自减操作及变量赋值,观察运算结果并理解其逻辑。
示例 1:简单的数值计算
# 直接计算1+1的结果并输出,$((...))会先计算内部表达式,再通过echo输出
[bq@shell ~]$ echo $((1+1))
2# 计算6*3的结果并输出
[bq@shell ~]$ echo $((6*3))
18# 用((...))定义变量i并赋值为5
[bq@shell ~]$ ((i=5))# 计算i*2的结果并重新赋值给i(此时i=5*2=10)
[bq@shell ~]$ ((i=i*2))# 输出变量i的值,验证运算结果
[bq@shell ~]$ echo $i
10
示例 2:复杂的数值计算
# 计算表达式1+2^3-4%3的结果并赋值给a(2^3=8,4%3=1,所以1+8-1=8)
[bq@shell ~]$ ((a=1+2**3-4%3))# 输出a的值,验证结果
[bq@shell ~]$ echo $a
8# 将表达式的结果同时赋值给b和a(先计算表达式,再赋值给a,最后将a的值赋给b)
[bq@shell ~]$ b=$((a=1+2**3-4%3))# 输出b的值,结果和a一致
[bq@shell ~]$ echo $b
8# 直接输出表达式的运算结果
[bq@shell ~]$ echo $((a=1+2**3-4%3))
8# 计算1到100的和(公式:n*(n+1)/2),赋值给a
[bq@shell ~]$ a=$((100*(100+1)/2))# 输出a的值(100*101/2=5050)
[bq@shell ~]$ echo $a
5050# 直接输出1到100的和
[bq@shell ~]$ echo $((100*(100+1)/2))
5050
示例 3:特殊运算符号的使用
# 定义a=8,然后计算a+=1(即a=a+1)的结果并输出(8+1=9)
[bq@shell ~]$ a=8;echo $((a+=1))
9# 计算a的平方(a此时为9,9^2=81)并输出
[bq@shell ~]$ echo $((a**2))
81
示例 4:比较和判断
# 判断3<8是否成立(成立),执行后无输出,通过$?查看返回值(0表示真)
[bq@shell ~]$ ((3<8))
[bq@shell ~]$ echo $? # $?是上一条命令的返回值,0为成功(真),非0为失败(假)
0# 直接输出3<8的判断结果(1表示真,0表示假)
[bq@shell ~]$ echo $((3<8))
1# 判断3>8是否成立(不成立),通过$?查看返回值(1表示假)
[bq@shell ~]$ ((3>8))
[bq@shell ~]$ echo $?
1# 直接输出3>8的判断结果(0表示假)
[bq@shell ~]$ echo $((3>8))
0# 输出3==3的判断结果(1表示真)
[bq@shell ~]$ echo $((3==3))
1# 用if判断8>7且5==5是否成立(成立则输出yes)
[bq@shell ~]$ if ((8>7 && 5==5));then echo yes;fi
yes
示例 5:自增(++)和自减(–)运算符的使用
# 定义a=10
[bq@shell ~]$ a=10# 输出a++的结果(a++是后置自增,先输出a的原值10,再将a加1)
[bq@shell ~]$ echo $((a++))
10# 此时a的值已变为11,输出验证
[bq@shell ~]$ echo $a
11# 输出--a的结果(--a是前置自减,先将a减1(11-1=10),再输出结果)
[bq@shell ~]$ echo $((--a))
10# 此时a的值为10,输出验证
[bq@shell ~]$ echo $a
10
总结:
- 后置自增 / 自减(
a++
、a--
):先输出变量当前值,再对变量进行加 1 / 减 1 操作。 - 前置自增 / 自减(
++a
、--a
):先对变量进行加 1 / 减 1 操作,再输出变量的新值。
示例 6:通过 $(()) 运算后赋值给变量
# 定义num=99
[bq@shell ~]$ num=99# 计算num+1的结果(99+1=100)并输出(此时num的值未改变)
[bq@shell ~]$ echo $((num+1))
100# 将num+1的结果赋值给num(此时num=100)
[bq@shell ~]$ num=$((num+1))# 输出num的值,验证结果
[bq@shell ~]$ echo $num
100
let 命令
let
命令用于执行整数运算,语法格式为 let 表达式
,其功能和 ((表达式))
完全相同。
实验流程:通过对比普通赋值和 let
命令赋值的差异,理解 let
命令的作用。
示例:
# 定义i=2
[bq@shell ~]$ i=2# 直接用i=i+8赋值(Shell会当作字符串处理,不会计算)
[bq@shell ~]$ i=i+8# 输出i的值,结果为字符串"i+8",而非计算后的10
[bq@shell ~]$ echo $i
i+8# 重新定义i=2
[bq@shell ~]$ i=2# 用let命令执行i=i+8(会进行数值计算,等价于((i=i+8)))
[bq@shell ~]$ let i=i+8# 输出i的值,结果为10(2+8=10)
[bq@shell ~]$ echo $i
10
expr 命令
expr
(全称 evaluate expressions,即 “求值表达式”)命令不仅可以进行整数运算,还能处理字符串长度计算、字符串匹配等操作。
expr 命令的基本用法
实验流程:通过简单的加减乘运算,观察 expr
命令的语法要求(如空格、特殊符号转义)。
示例:
# 计算2+2,但运算符前后没有空格,expr会当作字符串输出
[bq@shell ~]$ expr 2+2 # 等价于直接输出"2+2"
2+2# 计算2+2,运算符前后有空格,expr会进行数值计算并输出结果4
[bq@shell ~]$ expr 2 + 2 # 等价于echo $((2+2))
4# 直接用*计算2*2,会报错(*在Shell中是通配符,被误解)
[bq@shell ~]$ expr 2 * 2
expr: syntax error# 用\转义*,表示乘法,计算2*2的结果并输出4
[bq@shell ~]$ expr 2 \* 2
4
使用 expr
的注意事项:
- 运算符和参与计算的数字前后必须有至少一个空格,否则
expr
会当作字符串处理,不会进行运算。 - 乘法运算符
*
必须用反斜线\
转义,因为 Shell 中*
是通配符(匹配任意字符),不转义会被 Shell 误解。
expr 的企业级实战案例
实验流程:通过 4 个实战案例(判断整数、验证文件扩展名、计算字符串长度、筛选短单词),掌握 expr
在实际场景中的应用。
示例 1:判断一个变量值是否为整数
实现原理:expr
进行数值计算时,要求参与运算的必须是整数。如果将变量和一个已知整数(非 0)相加,若命令返回值为 0(成功),则变量为整数;若返回值非 0(失败),则变量不是整数。
# 定义变量i为整数5
[bq@shell ~]$ i=5# 用expr计算i+5(5+5=10),输出结果10
[bq@shell ~]$ expr $i + 5
10# 查看上一条命令的返回值(0表示成功,说明i是整数)
[bq@shell ~]$ echo $?
0# 定义变量i为非整数a
[bq@shell ~]$ i=a# 用expr计算i+5,因i不是整数,报错
[bq@shell ~]$ expr $i + 5
expr: non-integer argument# 查看返回值(2表示失败,说明i不是整数)
[bq@shell ~]$ echo $?
2
此外,还可以用 expr match
结合正则表达式判断是否为整数(^[0-9]+$
匹配 1 个或多个数字):
# 变量i为非整数a,用match匹配整数格式,返回0(不匹配)
[bq@shell ~]$ i=a
[bq@shell ~]$ expr match "$i" "^[1-9][0-9]*$" # ^[1-9][0-9]*$:匹配非0开头的整数(排除0)
0# 变量i为整数5,用match匹配整数格式,返回1(匹配成功,1表示匹配的长度)
[bq@shell ~]$ i=5
[bq@shell ~]$ expr match "$i" "^[0-9][0-9]*$" # ^[0-9][0-9]*$:匹配0或非0开头的整数(包括0)
1
示例 2:判断文件扩展名是否符合要求
通过 expr "$变量" : "正则表达式"
匹配字符串,若返回值大于 0 则匹配成功,否则失败。
# 定义文件名为stu-202212.jpg(扩展名是jpg)
[bq@shell ~]$ file=stu-202212.jpg# 用正则表达式".*\.jpg$"匹配以.jpg结尾的文件(.*匹配任意字符,\.jpg$匹配.jpg结尾)
# 返回值14表示匹配的字符串长度(整个文件名长度),说明匹配成功
[bq@shell ~]$ expr "$file" : ".*\.jpg$"
14# 查看返回值(0表示成功)
[bq@shell ~]$ echo $?
0# 用正则表达式".*\.pub$"匹配以.pub结尾的文件(当前文件不匹配)
# 返回值0表示未匹配
[bq@shell ~]$ expr "$file" : ".*\.pub$"
0# 查看返回值(1表示失败)
[bq@shell ~]$ echo $?
1
示例 3:计算字符串的长度
用 expr length "字符串"
可直接获取字符串的长度(字符个数)。
# 定义字符串str为"abc123abc123"
[bq@shell ~]$ str="abc123abc123"# 计算str的长度(a、b、c、1、2、3、a、b、c、1、2、3共12个字符)
[bq@shell ~]$ expr length "$str"
12
示例 4:打印字符数不大于 6 的单词
脚本功能:遍历字符串中的每个单词,用 expr length
计算单词长度,筛选出长度≤6 的单词并输出。
#!/bin/bash
# 定义要处理的字符串(包含多个单词)
strings="This is Linux World Welcome to our classroom"# 遍历字符串中的每个单词(for循环默认按空格分割)
for word in $strings
do# 用expr length计算单词长度,若长度≤6则输出该单词if [ $(expr length "$word") -le 6 ];thenecho $wordfi
done
执行验证:
# 执行脚本
[bq@shell ~]$ bash str.sh
This # 长度4(≤6)
is # 长度2(≤6)
Linux # 长度5(≤6)
World # 长度5(≤6)
to # 长度2(≤6)
our # 长度3(≤6)
说明:字符串中的单词长度分别为:This(4)、is(2)、Linux(5)、World(5)、Welcome(7,不输出)、to(2)、our(3)、classroom(10,不输出),因此输出符合条件的单词。
bc 命令
bc
是 Linux 自带的计算器程序,支持整数和小数运算,还可以通过 scale
控制小数位数。
实验流程:通过交互式和非交互式两种方式使用 bc
,演示整数、小数运算及小数位数控制。
示例:
# 进入bc交互式模式(输入bc后回车)
[bq@shell ~]$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. # 计算复杂表达式1+3*4-6/3^3%4(3^3=27,6/27=0,0%4=0,所以1+12-0=13)
1+3*4-6/3^3%4
13# 设置小数位数为4(scale控制小数位数)
scale=4# 计算1/3,结果保留4位小数
1/3
.3333# 退出bc交互式模式
quit# 非交互式模式:用echo将表达式传给bc,计算结果并输出
[bq@shell ~]$ echo '1+3*4-6/3^3%4' | bc
13# 非交互式模式:设置scale=4后计算1/3,结果保留4位小数
[bq@shell ~]$ echo 'scale=4;1/3' | bc
.3333
awk 命令实现计算
awk
是一种文本处理工具,同时也支持数值运算,尤其适合小数计算,精度较高。
实验流程:通过两个示例演示 awk
处理小数和整数运算的能力。
示例:
# 用echo传递两个小数7.7和3.8给awk,计算它们的差(7.7-3.8=3.9)
[bq@shell ~]$ echo 7.7 3.8 | awk '{ print $1-$2 }' # $1表示第一个参数,$2表示第二个参数
3.9# 传递两个整数358和113给awk,计算(358-3)/113的结果(355/113≈3.14159)
[bq@shell ~]$ echo 358 113 | awk '{ print ($1-3)/$2 }'
3.14159
$[] 符号的运算
$[]
是 Shell 中用于整数运算的符号,语法简单,用法和 $(())
类似。
实验流程:通过多个示例演示 $[]
的基本运算、变量参与运算及自增自减操作。
示例 1:基本运算
# 计算1+1的结果并输出
[bq@shell ~]$ echo $[1+1]
2# 计算4-2的结果并输出
[bq@shell ~]$ echo $[4-2]
2# 计算2*2的结果并输出
[bq@shell ~]$ echo $[2*2]
4# 计算4/2的结果并输出(整数除法,结果取整)
[bq@shell ~]$ echo $[4/2]
2# 计算5/2的结果并输出(5÷2=2.5,取整为2)
[bq@shell ~]$ echo $[5/2]
2# 计算5%2的结果并输出(5除以2的余数是1)
[bq@shell ~]$ echo $[5%2]
1# 定义count=3,计算(count+1)*3的结果((3+1)*3=12)
[bq@shell ~]$ count=3;echo $[(count+1)*3]
12# 前置自增:先将count加1(3+1=4),再计算4+3=7
[bq@shell ~]$ count=3;echo $[ ++count + 3 ]
7# 后置自增:先计算3+3=6,再将count加1(此时count=4)
[bq@shell ~]$ count=3;echo $[ count++ + 3 ]
6# 前置自减:先将count减1(3-1=2),再计算2+3=5
[bq@shell ~]$ count=3;echo $[ --count + 3 ]
5# 后置自减:先计算3+3=6,再将count减1(此时count=2)
[bq@shell ~]$ count=3;echo $[ count-- + 3 ]
6
示例 2:计算 1 到 10 的和并输出表达式及结果
要求:输出格式为 1+2+3+...+10=55
。
# 方法1:用seq -s "+" 10生成"1+2+...+10",通过bc计算结果,再用echo拼接
[bq@shell ~]$ echo "$(seq -s + 10)=$(seq -s + 10 | bc)"
1+2+3+4+5+6+7+8+9+10=55# 方法2:用{1..10}生成1到10,tr将空格转为+,再用$((...))计算结果
[bq@shell ~]$ echo "$(echo {1..10} | tr ' ' '+')=$(( $(echo {1..10} | tr ' ' '+' ) ))"
1+2+3+4+5+6+7+8+9+10=55# 方法3:用$[]计算结果,其余和方法2相同
[bq@shell ~]$ echo "$(echo {1..10} | tr ' ' '+')=$[ $(echo {1..10} | tr ' ' '+' ) ]"
1+2+3+4+5+6+7+8+9+10=55
验证说明:三种方法均能生成 1+2+...+10
的表达式,并计算出和为 55,符合预期结果。
如涉及版权问题,请联系作者处理!!!