变量的数值计算
1、算术运算符
如果要执行算术运算,就会离不开各种运算符号,和其他编程语言类似,Shell也有很多算术运算符,下面就给大家介绍一下常见的Shell算术运算符,如下表所示。

表中的算术运算符号均适用于常见的运算命令,那么,这里所说的运算命令又有哪些呢?见下表。

2、双小括号“(())”数值运算命令
2.1、双小括号“(())”数值运算的基础语法
双小括号“(())”的作用是进行数值运算与数值比较,它的效率很高,用法灵活,是企业场景运维人员经常采用的运算操作符,其操作方法见下表。

2.2、双小括号“(())”数值运算实践
范例:利用“(())”进行简单的数值计算。
[root@oldboy ~]# echo $((1+1)) #<==计算1+1后输出。
2 #<==结果为2。
[root@oldboy ~]# echo $((6-3)) #<==计算6-3后输出。
3 #<==结果为3。
[root@oldboy ~]# ((i=5))
[root@oldboy ~]# ((i=i*2)) #<==获取i值,然后计算i*2,再赋值给变量i,此时没有输出。
[root@oldboy ~]# echo $i #<==输出时才用echo,而且要加$。
10 #<==因为开始时i=5,所以,这里经过前一指令的计算后,i的结果为5*2=10。
范例:利用“(())”进行稍微复杂一些的综合算术运算。
[root@oldboy ~]# ((a=1+2**3-4%3))
#<==这是一个较复杂的表达式运算并赋值的操作,表达式运算后将结果赋值给a,先乘除后加减。
[root@oldboy ~]# echo $a
8 #<==运算后输出结果为8。
[root@oldboy ~]# b=$((1+2**3-4%3)) #<==这是另外一种表达式运算后将结果赋值给变量的写法,变量放在了括号的外面。
[root@oldboy ~]# echo $b
8
[root@oldboy ~]# echo $((1+2**3-4%3)) #<==还可以直接运算表达式并将结果输出,注意,不要落下了$符。
8
[root@oldboy ~]# a=$((100*(100+1)/2)) #<==利用公式计算1+2+3+...+100的和。
[root@oldboy ~]# echo $a
5050
[root@oldboy ~]# echo $((100*(100+1)/2)) #<==直接输出表达式的结果。
5050
范例:特殊运算符号的运算小示例。
[root@oldboy ~]# a=8
[root@oldboy ~]# echo $((a=a+1)) #<==将a+1赋值给a,然后输出表达式的值。
9
[root@oldboy ~]# echo $((a+=1)) #<==相当于a=a+1。
10
[root@oldboy ~]# echo $((a**2)) #<==计算a的平方,**表示幂运算。
100
范例5-4:利用“(())”双括号进行比较及判断。
[root@oldboy ~]# echo $((3<8)) #<==3<8的结果是成立的,因此,输出了1,1表示真。
1 #<==输出1说明上述表达式的结果是对的。
[root@oldboy ~]# echo $((8<3)) #<==8<3的结果是不成立的,因此,输出了0,0表示假。
0 #<==输出0说明上述表达式的结果是错的。
[root@oldboy ~]# echo $((8==8)) #<==判断是否相等。
1
[root@oldboy ~]# if ((8>7&&5==5)) #<==如果8>7成立并且5==5成立,则打印yes。显然这两个条件都成立。
> then #<==这是一个简单的命令行if语句格式。
> echo yes
> fi
yes #<==因此结果输出了yes。
提示:上面涉及的数字及变量必须为整数(整型),不能是小数(浮点数)或字符串。后面的bc和awk命令可以用于进行小数(浮点数)运算,但一般用到的较少,下文对此还会讲解。
例5-5:在变量前后使用–和++特殊运算符的表达式。
[root@oldboy ~]# a=10
[root@oldboy ~]# echo $((a++))
#<== 如果a在运算符(++或--)的前面,那么在输出整个表达式时,会输出a的值,因为a为10,所以表达式的值为10。
10
[root@oldboy ~]# echo $a #<==执行上面的表达式后,因为有a++,因此a会自增1,因此输出a的值为11。
11
[root@oldboy ~]# a=11
[root@oldboy ~]# echo $((a--))
#<== 如果a在运算符(++或--)的前面,那么在输出整个表达式时,会输出a的值,因为a为11,所以表达式的值的为11。
11
[root@oldboy ~]# echo $a #<==执行上面的表达式后,因为有a--,因此a会自动减1,因此a为10。
10
[root@oldboy ~]# a=10
[root@oldboy ~]# echo $a
10
[root@oldboy ~]# echo $((--a))
#<== 如果a在运算符(++或--)的后面,那么在输出整个表达式时,先进行自增或自减计算,因为a为10,且要自减,所以表达式的值为9。
9
[root@oldboy ~]# echo $a #<==执行上面的表达式后,a自减1,因此a为9。
9
[root@oldboy ~]# echo $((++a))
#<== 如果a在运算符(++或--)的后面,输出整个表达式时,先进行自增或自减计算,因为a为9,且要自增1,所以输出10。
10
[root@oldboy ~]# echo $a #<==执行上面的表达式后,a自增1,因此a为10。
10
执行echo $((a++))和echo $((a–))命令输出整个表达式时,输出的值即为a的值,表达式执行完毕后,会对a进行++、–的运算,而执行echo $((++a))和echo $((–a))命令输出整个表达式时,会先对a进行++、–的运算,然后再输出表达式的值,即为a运算后的值。
提示:有关++、–运算的记忆方法:
变量a在运算符之前,输出表达式的值为a,然后a自增或自减;变量a在运算符之后,输出表达式会先自增或自减,表达式的值就是自增或自减后a的值。
如果实在理解不了这里的++和–,跳过就可以了,不会影响读者学好Linux运维,在工作中,使用它们前先测试好结果即可。
范例:通过“(())”运算后赋值给变量。
[root@oldboy ~]# myvar=99
[root@oldboy ~]# echo $((myvar+1)) #<==“(())”中的变量myvar前也可以加$符号,也可以不加。
100
[root@oldboy ~]# echo $(( myvar + 1 )) #<==“(())”内部内容的两端有几个空格无所谓,变量和运算符号之间有无空格也无所谓,可以有一个或多个,也可以没有。
100
[root@oldboy ~]# myvar=$((myvar+1)) #<==还可以在“(())”表达式前加$符号,将表达式赋值给变量。
[root@oldboy ~]# echo $myvar
100
提示:在“(())”中使用变量时可以去掉变量前的$符号。
范例:包含“(())”的各种常见运算符命令行的执行示例。
[root@oldboy ~]# echo $((6+2)) #<==加法
8
[root@oldboy ~]# echo $((6-2)) #<==减法
4
[root@oldboy ~]# echo $((6*2)) #<==乘法
12
[root@oldboy ~]# echo $((6/2)) #<==除法,取商数
3
[root@oldboy ~]# echo $((6%2)) #<==取模,即余数
0
[root@oldboy ~]# echo $((6**2)) #<==幂运算
36
提示:
“(())”表达式在命令行执行时不需要加 符号,直接使用 ( ( 6 符号,直接使用((6%2))形式即可,但是如果需要输出,就要加 符号,直接使用((6符,例如:echo $((6%2))。
“(())”里的所有字符之间没有空格、有一个或多个空格都不会影响结果。
范例:各种“(())”运算的Shell脚本示例。
[root@oldboy scripts]# cat test.sh
#! /bin/bash
a=6 #<==在脚本中定义a和b两个变量并分别赋值。
b=2
echo "a-b=$(($a-$b))" #<==对定义的变量值进行各种符号运算,并通过表达式的形式输出,下同。
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
建议读者手动输入一遍这个脚本,并执行看看结果。这个例子很重要,后文经常会使用到,可保留起来备用。
其执行结果如下,看看能否理解该结果:
[root@oldboy scripts]# sh test.sh
a-b=4
a+b=8
a*b=12
a/b=3
a**b=36
a%b=0
范例:把范例5-8脚本中的a、b两个变量通过命令行脚本传参,以实现混合运算脚本的功能。
这是一个考察实战编程思想的综合实践考试题,将涉及前面提到的特殊位置参数变量的知识。
参考答案1:
[root@oldboy scripts]# cat test.sh
#! /bin/bash
a=$1 #<==直接把特殊位置参数变量$1赋值给a,
b=$2 #<==并且把特殊位置参数变量$2赋值给b,这样,脚本传参的内容就会赋值给a和b。
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
执行结果如下:
[root@oldboy scripts]# sh test.sh 6 2
a-b=4
a+b=8
a*b=12
a/b=3
a**b=36
a%b=0
[root@oldboy scripts]# sh test.sh 10 5
a-b=5
a+b=15
a*b=50
a/b=2
a**b=100000
a%b=0
使用脚本传参的好处是可以进行各种数字间的运算,不像前一个脚本,因为是直接定义变量的,所以只能做6和2这两个数字的运算,也就是说,使用传参,可以让脚本更具备通用性。
参考答案2:
#! /bin/bash
echo "a-b =$(( $1 - $2 ))"
echo "a+b =$(( $1 + $2 ))"
echo "a*b =$(( $1 * $2 ))"
echo "a/b =$(( $1 / $2 ))"
echo "a**b =$(( $1 ** $2 ))"
echo "a%b =$(( $1 % $2 ))"
范例:实现输入2个数进行加、减、乘、除功能的计算器。
#! /bin/bash
#add, subtract, multiply and divide by yubing 2013-07-13
print_usage(){ #<==定义一个函数,名字为print_usage。
printf "Please enter an integer\n" #<==打印符合脚本要求的提示信息。
exit 1 #<==以返回值1退出脚本,这个在前面讲特殊进程变量时已经讲过这个返回值的用法了。
}
read -p "Please input first number: " firstnum #<==读入第一个数字,本章后文将讲解read。
if [ -n "`echo $firstnum|sed 's/[0-9]//g'`" ]; then
#<==判断是否为整数,删除读入内容的数字部分看是否为空(-n功能),进而判断读入的内容是否为数字。
print_usage #<==如果上述条件变量值不为空,说明不是整数,则调用用户帮助函数。
fi
read -p "Please input the operators: " operators #<==继续读入运算符。
if [ "${operators}" ! = "+" ]&&[ "${operators}" ! = "-" ] && [ "${operators}"
!= "*" ] && [ "${operators}" ! = "/" ]; then #<==判断第二个输入内容操作符是否为+-*/任意运算符之一。
echo "please use {+|-|*|/}" #<==如果操作符不符合要求,则给出提示。
exit 2 #<==因为不符合要求,因此以返回值2退出脚本,表示出现错误了。
fi
read -p "Please input second number: " secondnum #<==读入第二个要运算的数字。
if [ -n "`echo $secondnum|sed 's/[0-9]//g'`" ]; then #<==同第一个运算的数字,判断是否为整数。
print_usage #<==如果上述条件变量值不为空,说明不是整数,则调用用户帮助函数。
fi
echo "${firstnum}${operators}${secondnum}=$((${firstnum}${operators}${seco
ndnum}))" #<==上述条件都符合后,进入运算,输出运算表达式和计算结果。
3、let运算命令的用法
let运算命令的语法格式为:let赋值表达式
let赋值表达式的功能等同于“((赋值表达式))”。
范例:给自变量i加8。
[root@oldboy scripts]# i=2
[root@oldboy scripts]# i=i+8 #<==假如开头不用let进行赋值。
[root@oldboy scripts]# echo $i #<==输出时会发现,打印结果为i+8,也就是没有计算。
i+8
[root@oldboy scripts]# unset i
[root@oldboy scripts]# i=2
[root@oldboy scripts]# let i=i+8 #<==采用let赋值后再输出。
[root@oldboy scripts]# echo $i
10 #<==结果为10
提示:let i=i+8等同于((i=i+8)),但后者效率更高。
范例:监控Web服务状态,如果访问两次均失败,则报警(let应用案例)。
[root@oldboy scripts]# cat 05_12_checkurl.sh
CheckUrl() { #<==定义函数,名字为CheckUrl。
timeout=5 #<==定义wget访问的超时时间,超时就退出。
fails=0 #<==初始化访问网站失败的次数记录变量,若失败达到两次,就发邮件报警。
success=0 #<==初始化访问网站成功的次数记录变量,如果为1,则表示成功,退出脚本。
while true #<==持续循环检测。
do
wget --timeout=$timeout --tries=1 http://oldboy.blog.51cto.com -q -O /dev/null
#<==使用wget测试访问老男孩的博客地址。
if [ $? -ne 0 ] #<==如果上述wget命令执行不成功,即返回值不为0,则执行if语句内的指令。
then
let fails=fails+1 #<==将访问失败的次数加1,这个就是let的用法,可以用((fails=fails+1))代替。
else
let success+=1 #<==返回值不为0则不成立,即访问成功,将成功的次数加1。
fi
if [ $success -ge 1 ] #<==如果成功的次数大于等于1
then
echo success #<==则打印成功标识,这也可以用冒号(:)替代,不输出结果,这是为了观察方便。
exit 0 #<==返回0值,退出脚本,表示检测成功。
fi
if [ $fails -ge 2 ] #<==如果失败的次数大于等于2,则报警。
then
Critical="sys is down."
echo $Critical|tee|mail -s "$Critical" abc@oldboyedu.com
#<==输出并发邮件报警,这里需要单独配你自己的邮箱地址,别用作者这里写的。
exit 2
fi
done
}
CheckUrl #<==执行函数。
提示:实际上wget命令有自动重试的功能,–tries=1参数就是,这里以一个脚本为大家阐述编程思想及let的应用案例。
4、expr命令的用法
4.1、expr命令的基本用法示例
expr(evaluate(求值)expressions(表达式))命令既可以用于整数运算,也可以用于相关字符串长度、匹配等的运算处理。
4.1.1、expr用于计算
语法:
expr Expression
范例:expr命令运算用法实践。
[root@oldboy scripts]# expr 2 + 2
4
[root@oldboy scripts]# expr 2 - 2
0
[root@oldboy scripts]# expr 2 * 2 #<==*号用\来转义。
expr: 语法错误
[root@oldboy scripts]# expr 2 \* 2
4
[root@oldboy scripts]# expr 2 / 2
1
要注意,在使用expr时:
- 运算符及用于计算的数字左右都至少有一个空格,否则会报错。
- 使用乘号时,必须用反斜线屏蔽其特定含义,因为Shell可能会误解星号的含义。
4.1.2、expr配合变量计算
expr在Shell中可配合变量进行计算,但需要用反引号将计算表达式括起来。
范例:给自变量i加6。
[root@oldboy scripts]# i=5
[root@oldboy scripts]# i=`expr $i + 6` #<==注意用反引号将表达式引起来,变量和数字符号两边要有空格。
[root@oldboy scripts]# echo $i
11
4.2、expr的企业级实战案例详解
4.2.1、判断一个变量值或字符串是否为整数
在Shell编程里,由于函数库很少,所以判断字符串是否为整数就不是一件很容易的事情。在这里,老男孩为读者介绍一种简单的可以判断一个字符串是否为整数的方法。
实现原理是,利用以expr做计算时变量或字符串必须是整数的规则,把一个变量或字符串和一个已知的整数(非0)相加,看命令返回的值是否为0。如果为0,就认为做加法的变量或字符串为整数,否则就不是整数。下面给出几个示例。
范例:通过expr判断变量或字符串是否为整数。
[root@oldboy scripts]# i=5 #<==赋值一个数5给i。
[root@oldboy scripts]# expr $i + 6 &>/dev/null #<==把i和整数相加,&>/dev/null表示不保留任何输出。
[root@oldboy scripts]# echo $? #<==输出返回值。
0 #<==返回为0,则证明i的值为整数。
[root@oldboy scripts]# i=oldboy #<==此时赋值一个字符串给i。
[root@oldboy scripts]# expr $i + 6 &>/dev/null #<==同样把i和整数相加,不保留任何输出。
[root@oldboy scripts]# echo $? #<==输出返回值。
2 #<==返回为非0,则证明i的值不是整数,因为赋值的是oldboy。
结论:利用expr做计算,将一个未知的变量和一个已知的整数相加,看返回值是否为0,如果为0就认为做加法的变量为整数,否则就不是整数。
范例:通过传参判断输出内容是否为整数。
[root@oldboy scripts]# cat 05_16_expr.sh
#! /bin/sh
expr $1 + 1 >/dev/null 2>&1
[ $? -eq 0 ] &&echo int||echo chars #<==这是一个条件表达式语法,返回值为0,则输出int,否则输出chars。
[root@oldboy scripts]# sh 05_16_expr.sh oldboy #<==传入oldboy字符。
chars #<==返回的是字符
[root@oldboy scripts]# sh 05_16_expr.sh 119 #<==传入119。
int #<==返回的是数字
范例:通过read读入持续等待输入例子
[root@oldboy scripts]# cat judge_int.sh
#! /bin/sh
while true
do
read -p "Pls input:" a
expr $a + 0 >/dev/null 2>&1
[ $? -eq 0 ] && echo int || echo chars
done
执行结果如下:
[root@oldboy scripts]# sh judge_int.sh
Pls input:oldgirl
chars
Pls input:120
int
Pls input:
范例:将前文的混合运算小程序改成输入两个参数后进行计算的程序,并且要能判断传参的个数及通过expr判断传入的参数是否为整数。
待使用的脚本如下:
[root@oldboy scripts]# cat test.sh
#! /bin/bash
a=6 #<==在脚本中定义a和b两个变量并分别赋值。
b=2
echo "a-b=$(($a-$b))" #<==对定义的变量值进行四则运算,并通过表达式的形式输出,下同。
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
这道题可以使用游戏过关的思想来编程解决。
编程思路:
- 第一关,判断参数个数是否为2,若不是,则给出提示终止运行。
- 第二关,判断传入的参数是否为整数,若不是,则给出提示终止运行。
- 第三关,做运算。
[root@oldboy scripts]# cat 05_18_1.sh
#! /bin/bash
#no.1
[ $# -ne 2 ] &&{ #<==对传入参数的个数进行判断,是否等于2。
echo $"USAGE $0 NUM1 NUM2" #<==若不满足条件,则打印提示。
exit 1 #<==以返回值1退出脚本,表示脚本执行错误。
}
#no.2
a=$1 #<==获取脚本传参的$1并赋值给a。
b=$2 #<==获取脚本传参的$2并赋值给b。
expr $a + $b + 110 &>/dev/null #<==将两个参数一起和110相加。
if [ $? -ne 0 ] #<==如果返回值不为0,则至少有一个不是整数。
then
echo "you must input two nums." #<==打印提示。
exit 2 #<==以返回值2退出脚本,表示脚本执行错误,为什么不用1呢,这里是为了区分前面的1,便于调试。
fi
#no.3
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
4.2.2、expr的特殊用法:判断文件扩展命名是否符合要求
范例:通过expr判断文件扩展名是否符合要求。
[root@oldboy scripts]# cat expr1.sh
#! /bin/sh
if expr "$1" : ".*\.pub" &>/dev/null
then
echo "you are using $1"
else
echo "pls use *.pub file"
fi
[root@oldboy scripts]# sh expr1.sh id_dsa.pub
you are using id_dsa.pub
[root@oldboy scripts]# sh expr1.sh id_dsa
pls use *.pub file
范例:使用expr命令实现系统ssh服务自带的ssh-copy-id公钥分发脚本。
[root@oldboy scripts]# sed -n '10,20p' `which ssh-copy-id`
if [ "-i" = "$1" ]; then
shift
# check if we have 2 parameters left, if so the first is the new ID file
if [ -n "$2" ]; then
if expr "$1" : ".*\.pub" > /dev/null ; then #<==判断脚本传入的$1是否符合
.pub扩展名。
# man expr结果。
# STRING : REGEXP
# anchored pattern match of REGEXP in STRING
ID_FILE="$1"
else
ID_FILE="$1.pub" #<==如果扩展名不符合要求,则自动加上扩展名,以防止用户发送私钥。
fi
shift # and this should leave $1 as the target name
fi
4.2.3、通过expr计算字符串的长度
范例:利用expr计算字符串的长度。
[root@oldboy scripts]# char="I am oldboy"
[root@oldboy scripts]# expr length "$char" #<==利用expr的length函数计算字符
串长度。
11
[root@oldboy scripts]# echo ${#char} #<==计算变量子串长度的方法。
11
[root@oldboy scripts]# echo ${char}|wc -L #<==wc方法
11
[root@oldboy scripts]# echo ${char}|awk '{print length($0)}' #<==利用awk的length函数来计算字符串的长度。
11
范例:请编写Shell脚本,打印下面语句中字符数不大于6的单词。
I am oldboy linux welcome to our training
[root@oldboy scripts]# cat word_length.sh
for n in I am oldboy linux welcome to our training
do
if [ `expr length $n` -le 6 ] #<==利用expr的length函数计算字符串长度,并输出长度不大于6的字符串。
then
echo $n
fi
done
执行结果如下:
[root@oldboy scripts]# sh word_length.sh
I
am
oldboy
linux
to
our
5、bc命令的用法
bc是UNIX/Linux下的计算器,因此,除了可以作为计算器来使用,还可以作为命令行计算工具使用。
范例:将bc作为计算器来应用。
[root@oldboy scripts]# bc #<==执行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+1 #<==输入1+1,按回车键计算。
2
3*3 #<==输入3+3回车后计算。
9
范例:将bc用在命令行下面,以实现运算功能。
[root@oldboy scripts]# echo 3+5|bc
8
[root@oldboy scripts]# echo 3.3+5.5|bc
8.8
[root@oldboy scripts]# echo 8.8-5.5|bc
3.3
[root@oldboy scripts]# echo "scale=2;355/113"|bc #<==使用scale=2保留两位小数。
3.14
[root@oldboy scripts]# echo "scale=6;355/113"|bc #<==使用scale=6保留6位小数。
3.141592
利用bc配合变量运算:
[root@oldboy scripts]# i=5
[root@oldboy scripts]# i=`echo $i+6|bc` #<==利用echo输出表达式,通过管道交给bc计算。此方法效率较低。
[root@oldboy scripts]# echo $i
11
提示:根据bc所具有的特殊性来看,如果是小数,则选择bc运算没有问题(老男孩推荐awk);若是整数场景,可用“(())”、let、expr等。
范例:通过一条命令计算输出1+2+3+…+10的表达式,并计算出结果,请使用bc命令计算。输出内容如1+2+3+4+5+6+7+8+9+10=55。
这里生成1+2+3+4+5+6+7+8+9+10表达式的方法有:
[root@oldboy scripts]# seq -s "+" 10 #<== seq是生成数字序列,-s是指定数字序列之间的分隔符。
1+2+3+4+5+6+7+8+9+10
[root@oldboy scripts]# echo {1..10}|tr " " "+"
#<=={1..10}是生成以空格为间隔的数字序列,并交给tr将空格替换为+号。
1+2+3+4+5+6+7+8+9+10
实现本题的多种方法如下:
[root@oldboy scripts]# echo `seq -s '+' 10`=`seq -s "+" 10|bc` #<==使用bc计算
1+2+3+4+5+6+7+8+9+10=55
[root@oldboy scripts]# echo "`seq -s '+' 10`="$((`seq -s "+" 10`))#<==使用“(())”计算
1+2+3+4+5+6+7+8+9+10=55
[root@oldboy scripts]# echo `seq -s '+' 10`=`seq -s " + " 10|xargs expr`#<==使用expr计算
1+2+3+4+5+6+7+8+9+10=55
[root@oldboy scripts]# echo `seq -s "+" 10`=$(echo $[`seq -s "+" 10`])#<==使用$[]计算
1+2+3+4+5+6+7+8+9+10=55
bc命令的独有特点是除了支持整数运算之外,还支持小数运算。
6、awk实现计算
利用awk进行运算的效果也很好,适合小数和整数,特别是命令行计算,尤其是小数,运算很精确,好用。来看个示例,如下:
[root@oldboy scripts]# echo "7.7 3.8" |awk '{print ($1-$2)}'
#<==$1为第一个数字,$2为第二个数字,用空格隔开,下同。
3.9
[root@oldboy scripts]# echo "358 113" |awk '{print ($1-3)/$2}'
3.14159
[root@oldboy scripts]# echo "3 9" |awk '{print ($1+3)*$2}'
54
7、declare(同typeset)命令的用法
下面将要讲解的是使用typeset定义整数变量,直接进行计算。这个方法不是很常用,因为需要定义才能生效。示例如下:
[root@oldboy scripts]# declare -i A=30 B=7 #<==declare -i参数可以将变量定义为整形。
[root@oldboy scripts]# A=A+B #<==因为已声明是整型,因此可以直接进行运算了。
[root@oldboy scripts]# echo $A
37 #<==结果为37(老男孩37岁了,还在奋斗。)
8、$[]符号的运算示例
关于$[]符号运算的示例如下:
[root@oldboy scripts]# i=5
[root@oldboy scripts]# i=$[i+6]
[root@oldboy scripts]# echo $i
11
[root@oldboy scripts]# echo $[2*3]
6
[root@oldboy scripts]# echo $[2**3]
8
[root@oldboy scripts]# echo $[3/5]
0
[root@oldboy scripts]# echo $[3/2]
1
[root@oldboy scripts]# echo $[3%5]
3
[root@oldboy scripts]# echo $[ 3 % 5 ]
3
下面是一个解决实际问题的示例:打印数学杨辉三角。
#! /bin/bash
if (test -z $1) ; then #<==判断传参的值长度是不是为0,如果没有传入参数,则使用read读入。
read -p "Input Max Lines:" MAX #<==read读入一个数值。
else
MAX=$1 #<==如果已经传参了,就把传参的$1赋值给MAX。
fi
#<==上述脚本很巧妙地通过判断,实现了用户既可以传参输入,也可以read读入数字。
i=1
while [ $i -le $MAX ] #<==i行控制。
do
j=1
while [ $j -le $i ] #<==j列控制。
do
f=$[i-1] #<==f=i-1是$[]计算写法。
g=$[j-1] #<==g=j-1是$[]计算写法。
if [ $j -eq $i ] || [ $j -eq 1 ] ; then
declare SUM_${i}_$j=1 #<==声明变量头尾都是1。
else
declare A=$[SUM_${f}_$j] #<==取上一行的j列变量。
declare B=$[SUM_${f}_$g] #<==取上一行的j-1列变量。
declare SUM_${i}_$j=`expr $A + $B` #<==声明并计算当前变量的值。
fi
echo -en $[SUM_${i}_$j]" " #<==输出当前变量。
let j++ #<==let运算用法。
done
echo #<==换行。
let i++ #<==let运算用法。
done
9、基于Shell变量输入read命令的运算实践
9.1、read命令基础
Shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入中获得,read为bash内置命令,可通过help read查看帮助。
语法格式:
read [参数] [变量名]
常用参数如下。
- -p prompt:设置提示信息。
- -t timeout:设置输入等待的时间,单位默认为秒。
范例:实现read的基本读入功能。
[root@oldboy scripts]# read -t 10 -p "Pls input one num:" num
#<==读入一个输入,赋值给num变量,注意,num变量前需要有空格。
Pls input one num:18 #<==输出数字18,相当于把18赋值给num变量。
[root@oldboy scripts]# echo $num #<==输出变量值。
[root@oldboy scripts]# read -p "please input two number:" a1 a2
#<==读入两个输入,注意要以空格隔开,分别赋值给a1和a2变量,a1变量前后都需要有空格。
please input two number:1 2
[root@oldboy scripts]# echo $a1
1
[root@oldboy scripts]# echo $a2
2
提示:read的读入功能就相当于交互式接受用户输入,然后给变量赋值。
上面read -p的功能可以用echo和read来实现,如下:
echo -n "please input two number:"
read a1 a2
以上两句和下面的命令相当(-t排除在外)。
read -t 5 -p "please input two number:" a1 a2 #5秒超时退出
范例:把前面加减乘除计算传参的脚本改成通过read方式读入整数变量。
原始脚本如下:
#! /bin/bash
a=$1
b=$2
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
解答:
[root@oldboy scripts]# cat test_2.sh
#! /bin/bash
read -t 15 -p "please input two number:" a b #<==去掉原脚本中a和b的定义,通过read读入即可。
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
[root@oldboy scripts]# sh test_2.sh
please input two number:10 5
a-b=5
a+b=15
a*b=50
a/b=2
a**b=100000
a%b=0
9.2、以read命令读入及传参的综合企业案例
先来思考一下:如果前面范例中读入的不是整数或者输入的数字个数不是2,那么执行脚本会有什么结果?又该如何解决呢?
其实,这里要用到的思想在讲解expr命令时已经提到过了,这里再以其他方法进行讲解。
该问题同样可用打游戏过关的思路来解决。
- 第一关:若用户按要求输入了两个值,则过关,否则game over。
编程提示:可以用变量的子串长度知识,例如:${#OLDBOY}。 - 第二关:用户输入的内容均为整数,才能过关,否则game over。
解答过程如下。
以read命令进行读入判断。
[root@oldboy scripts]# cat read_size01.sh
#! /bin/bash
read -t 15 -p "Please input two number:" a b
#no1
[ ${#a} -le 0 ]&&{ #<==利用条件表达式,根据变量值的长度是否小于0,来确定第一个数是否为空。
echo "the first num is null"
exit 1
}
[ ${#b} -le 0 ]&&{ #<==利用条件表达式,根据变量值的长度是否小于0,来确定第二个数是否为空。
echo "then second num is null"
exit 1
}
#no2 #<==这里的用法在前面已详细注释过,因此这里不再注释。
expr $a + 1 &>/dev/null
RETVAL_A=$?
expr $b + 1 &>/dev/null
RETVAL_B=$?
if [ $RETVAL_A -ne 0 -o $RETVAL_B -ne 0 ]; then
echo "one of the num is not num, pls input again."
exit 1
fi
#no.3
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a/b=$(($a/$b))"
echo "a**b=$(($a**$b))"
echo "a%b=$(($a%$b))"
执行结果如下:
[root@oldboy scripts]# sh read_size01.sh
Please input two number:qq #<==若输入非数字,则会报错。
then second num is null
[root@oldboy scripts]# sh read_size01.sh
Please input two number:qq dd
one of the num is not num, pls input again.
[root@oldboy scripts]# sh read_size01.sh
Please input two number:12 6
a-b=6
a+b=18
a*b=72
a/b=2
a**b=2985984
a%b=0
再来思考一下:如何将上述read读入改用脚本传参的方法来实现呢?
此题前文已经给过答案,这里给出其他脚本方法,如下:
[root@oldboy scripts]# cat read_size02.sh
#! /bin/bash
a=$1 #<==将$1赋值给a。
b=$2 #<==将$2赋值给b。
Usage(){ #<==定义帮助函数。
echo $"USAGE:sh $0 num1 num2" #<==输出帮助,$0表示脚本名。
exit 1 #<==以1作为返回值退出脚本。
}
if [ $# -ne 2 ]; then #<==参数个数不等于2,打印帮助。
Usage
fi
expr $a + 1 >/dev/null 2>&1
[ $? -ne 0 ] && Usage
expr $b + 0 >/dev/null 2>&1 #<==这个地方使用的加0,是为了防止b为0而导致被除数为0。
[ $? -ne 0 ] && Usage
#no.3
echo "a-b=$(($a-$b))"
echo "a+b=$(($a+$b))"
echo "a*b=$(($a*$b))"
echo "a**b=$(($a**$b))"
if [ $b -eq 0 ] #<==这个地方对b做了个判断,防止被除数为0,算是个保险吧,可能用不上。
then
echo "your input does not allow to run."
echo "a/b =error"
echo "a%b =error"
else
echo "a/b =$(($a/$b))"
echo "%b =$(($a%$b))"
fi
执行结果如下:
[root@oldboy scripts]# sh read_size02.sh
USAGE:sh read_size02.sh num1 num2
[root@oldboy scripts]# sh read_size02.sh 7 oldboy
USAGE:sh read_size02.sh num1 num2
[root@oldboy scripts]# sh read_size02.sh 7 3
a-b=4
a+b=10
a*b=21
a**b=343
a/b =2
a%b =1
[root@oldboy scripts]# sh read_size02.sh 7 0
USAGE:sh read_size02.sh num1 num2

4372

被折叠的 条评论
为什么被折叠?



