一算术运算
bash中的算术运算:help let
+, -, *, /, %取模(取余), **(乘方)
实现算术运算:
(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 ...)
(5) declare –i var = 数值
(6) echo ‘算术表达式’ | bc
乘法符号有些场景中需要转义,如*
bash有内建的随机数生成器:$RANDOM(0-32767)
echo $[$RANDOM%50] :0-49之间随机数
(一) let var=算术表达式
使用let
变量前面可以不加$,因为let知道是数字运算,出现像n,m这样的字母了就认为是变量。
[root@centos73 shell_scripts]# n=20 [root@centos73 shell_scripts]# m=30 [root@centos73 shell_scripts]# let sum=n+m [root@centos73 shell_scripts]# echo $sum 50 [root@centos73 shell_scripts]#
使用let取余数
[root@centos73 shell_scripts]# n=20 [root@centos73 shell_scripts]# m=30 [root@centos73 shell_scripts]# let sum=n+m [root@centos73 shell_scripts]# echo $sum 50 [root@centos73 shell_scripts]# let i=m%7 [root@centos73 shell_scripts]# echo $i 2 [root@centos73 shell_scripts]# let j=2**6 [root@centos73 shell_scripts]# echo $j 64
(二)var=$[算术表达式]
[root@centos73 shell_scripts]# echo $[1+2] 3 [root@centos73 shell_scripts]# echo $[3*4] 12 [root@centos73 shell_scripts]# echo $[n*m] 600 [root@centos73 shell_scripts]# echo $[n-m] -10 [root@centos73 shell_scripts]# echo $[m-n] 10
(三)var=$((算术表达式))
[root@centos73 shell_scripts]# echo $((m-n)) 10 [root@centos73 shell_scripts]# echo $((1+2)) 3 [root@centos73 shell_scripts]# echo $((3*4)) 12 [root@centos73 shell_scripts]# echo $((n*m)) 600
(四)var=$(expr arg1 arg2 arg3 ...)
expr本身是一个命令,可以直接进行运算
[root@centos73 ~]# expr 1+2 1+2 [root@centos73 ~]# expr 1 + 2注意要空格才可以进行运算。乘法符号有些场景中需要转义,如*。也就是expr这个命令后面跟的是3个参数 3
[root@centos73 ~]# expr 3 * 2 expr: syntax error [root@centos73 ~]# expr 3 * 2因为该命令认为*是通配符了,所以要使用反斜线进行转义。 6 [root@centos73 ~]# expr 3 * 2 expr: syntax error
(五)declare –i var = 数值
declare用来声明变量是数字变量。把变量声明成整数是一个很好的习惯,因为系统默认是把数字当成字符串的。
[root@centos73 ~]# declare -i n=10 [root@centos73 ~]# declare -i m=20 [root@centos73 ~]# let sum=n+m [root@centos73 ~]# echo $sum 30
(六) echo ‘算术表达式’ | bc
实际上是调用bc这个计算器了
[root@centos73 ~]# declare -i n=10 [root@centos73 ~]# declare -i m=20 [root@centos73 ~]# let sum=n+m [root@centos73 ~]# echo $su $suffix $sum [root@centos73 ~]# echo $sum 30 [root@centos73 ~]# echo $m+$n 20+10 [root@centos73 ~]# echo $m+$n | bc 30
(七)bash有内建的随机数生成器:$RANDOM(0-32767)
在命令行输入man bash,/RANDOM来查看RANDOM的信息。
RANDOM Each time this parameter is referenced, a random integer between 0 and 32767 is generated.
The sequence of random numbers may be initialized by assigning a value to RANDOM.
If RANDOM is unset, it loses its special properties, even if it is subsequently reset.
echo $[$RANDOM%50] :0-49之间随机数。注意每次都是随机值。
[root@centos73 ~]# echo $[RANDOM%50]
25
[root@centos73 ~]# echo $[RANDOM%50]
37
[root@centos73 ~]# echo $[RANDOM%50]
24
[root@centos73 ~]# echo $[RANDOM%50]
33
[root@centos73 ~]# echo $[RANDOM%50]
29
[root@centos73 ~]# echo $[RANDOM%50]
21
echo $[$RANDOM%50+1] :1-50之间随机数。中括号里面的RANDOM加不加$显示的结果都一样的。
[root@centos73 ~]# echo $[$RANDOM%50+1]
18
[root@centos73 ~]# echo $[$RANDOM%50+1]
13
[root@centos73 ~]# echo $[$RANDOM%50+1]
11
[root@centos73 ~]# echo $[$RANDOM%50+1]
48
[root@centos73 ~]# echo $[$RANDOM%50+1]
9
[root@centos73 ~]# echo $[$RANDOM%50+1]
23
[root@centos73 ~]# echo $[$RANDOM%50+1]
12
二赋值
(一)增强型赋值
增强型赋值:+=, -=, *=, /=, %=
let i+=3 ↔ let i=i+3两个表达式是等价的,就是把自己加上3再赋给自己
[root@centos73 ~]# echo $n
10
[root@centos73 ~]# let i+=3
[root@centos73 ~]# echo $n
10
[root@centos73 ~]# let n+=3
[root@centos73 ~]# echo $n
13
[root@centos73 ~]# echo $n;let n+=14
13
[root@centos73 ~]# echo $n
27
let i-=3 ↔ let i=i-3两个表达式是等价的,就是把自己加上3再赋给自己。
[root@centos73 ~]# echo $n
27
[root@centos73 ~]# echo $n;let n-=10
27
[root@centos73 ~]# echo $n
17
(二)自增自减
自增,自减:let var +=1,let var ++,let var -=1,let var --i++相当于i=i+1
[root@centos73 ~]# let n++;echo $n
18
[root@centos73 ~]# let n++;echo $n
19
[root@centos73 ~]# let n++;echo $n
20
[root@centos73 ~]# let n++;echo $n
21
[root@centos73 ~]# let n++;echo $n
22
示例
1、编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和
法1:
涉及知识点:(二)var=$[算术表达式]
[root@centos73 ~]# head /etc/passwd | tail -1 | cut -d: -f3 11
赋到一个变量去,比如这是第10个用户的ID,变量名为UID10.
[root@centos73 ~]# UID10=`head /etc/passwd | tail -1 | cut -d: -f3`
[root@centos73 ~]# UID20=`head -20 /etc/passwd | tail -1 | cut -d: -f3`
[root@centos73 ~]# echo $[UID10+UID20]
38
完整的脚本:
[root@centos73 shell_scripts]# cat sumid.sh
#!/bin/bash
#Author=wang
uid_10=`cat /etc/passwd |head -n 10 |tail -n 1 |cut -d ":" -f 3`
uid_20=`cat /etc/passwd |head -n 20 |tail -n 1 |cut -d ":" -f 3`
sum_id=$[uid_10+uid_20]
echo $sum_id
[root@centos73 shell_scripts]# bash sumid.sh
59
法2:使用awk
涉及知识点:增强型赋值
[root@centos73 shell_scripts]# cat sumid_awk.sh
#!/bin/bash
#Author=wang
cat /etc/passwd |awk -F ":" ' {if(NR==10 || NR==20 ){sum+=$3}} END{print sum}'
[root@centos73 shell_scripts]# bash sumid_awk.sh
59
2、编写脚本sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和
涉及知识点:(二)var=$[算术表达式]
完整脚本文件:
[root@centos73 shell_scripts]# cat sumspace.sh
#!/bin/bash
#Author=wang
file1_space_line=`cat $1 |grep "^$" |wc -l`
file2_space_line=`cat $2 |grep "^$" |wc -l`
sum_space_line=$[file1_space_line+file2_space_line]
echo $sum_space_line
执行结果:
[root@centos73 shell_scripts]# bash sumspace.sh /etc/fstab /etc/issue
2
[root@centos73 shell_scripts]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Jan 9 13:54:32 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=154fb900-77cf-4d55-975f-b788805fe281 / xfs defaults 0 0
UUID=f0c8487e-df2a-4042-81ca-f9011445c8bd /app xfs defaults 0 0
UUID=e76ffa1a-9169-42d4-adcc-c6bdbfefd663 /boot xfs defaults 0 0
UUID=809c994a-336d-4517-b3c4-7e0dae5ad738 swap swap defaults 0 0
/dev/cdrom /mnt iso9660 defaults 0 0
[root@centos73 shell_scripts]# cat /etc/issue
S
Kernel
on an m
3、编写脚本sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件
涉及知识点:(二)var=$[算术表达式]
完整脚本:
[root@centos73 shell_scripts]# cat sumfile.sh
#!/bin/bash
#Author=wang
let sumfiles=$[`ls -A -1 /etc |wc -l`]+$[`ls -A -1 /usr | wc -l`]+$[`ls -A -1 /var |wc -l`]
echo $sumfiles
执行结果:
[root@centos73 shell_scripts]# bash sumfile.sh
225
执行过程:
[root@centos73 shell_scripts]# bash -x sumfile.sh
++ ls -A -1 /etc
++ wc -l
++ ls -A -1 /usr
++ wc -l
++ ls -A -1 /var
++ wc -l
+ let sumfiles=190+12+23
+ echo 225
225
脚本解析:
ls的选项:
-A, --almost-all
do not list implied . and ..
-1 list one file per line
[root@centos73 shell_scripts]# ls -A -1 /var
adm
cache
crash
db
empty
ftp
games
gopher
kerberos
lib
local
lock
log
mail
nis
opt
preserve
run
spool
tmp
.updated
www
yp
三逻辑运算
(一)真假
true, false
1, 0
(二)与
1 与 1 = 1
1 与 0 = 0
0 与 1 = 0
0 与 0 = 0
(三)或
1 或 1 = 1
1 或 0 = 1
0 或 1 = 1
0 或 0 = 0
(四)非:!
! 1 = 0
! 0 = 1
(五)短路运算
1短路与
第一个为0,结果必定为0
第一个为1,第二个必须要参与运算
&& 代表条件性的AND THEN,也就是短路与
cmd1 短路与 cmd2
如果cmd1 为假,将不执行cmd2
如果cmd1 为真,将执行cmd2
只有命令1执行成功了才会执行命令2,比如如果一个用户是存在的,就执行删除
[root@centos7 bin]# ls hello.sh ping.sh sum1.sh sum.sh systeminfo.sh [root@centos7 bin]# id wang && user useradd userdel userhelper usermod usernetctl users [root@centos7 bin]# id wang && userdel -r wang id: wang: no such user [root@centos7 bin]# useradd wang [root@centos7 bin]# id wang && userdel -r wang uid=1002(wang) gid=1002(wang) groups=1002(wang) [root@centos7 bin]# id wang && userdel -r wang id: wang: no such user
查看用户是否在文件中存在,如果存在就显示后面的命令
[root@centos7 bin]# grep -q root /etc/passwd && echo hahaha
hahaha
ping脚本
[root@centos7 ~]# ping 172.25.67.47 -c3 PING 172.25.67.47 (172.25.67.47) 56(84) bytes of data. 64 bytes from 172.25.67.47: icmp_seq=1 ttl=64 time=0.299 ms 64 bytes from 172.25.67.47: icmp_seq=2 ttl=64 time=0.210 ms 64 bytes from 172.25.67.47: icmp_seq=3 ttl=64 time=0.276 ms --- 172.25.67.47 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2000ms rtt min/avg/max/mdev = 0.210/0.261/0.299/0.042 ms [root@centos7 ~]# ping 172.25.67.47 -c3 & > /dev/null
#注意&>是连在一起的 [1] 21303 [root@centos7 ~]# PING 172.25.67.47 (172.25.67.47) 56(84) bytes of data. 64 bytes from 172.25.67.47: icmp_seq=1 ttl=64 time=0.271 ms 64 bytes from 172.25.67.47: icmp_seq=2 ttl=64 time=0.287 ms 64 bytes from 172.25.67.47: icmp_seq=3 ttl=64 time=0.315 ms --- 172.25.67.47 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2001ms rtt min/avg/max/mdev = 0.271/0.291/0.315/0.018 ms ^C [1]+ Done ping 172.25.67.47 -c3 [root@centos7 ~]# ping 172.25.67.47 -c3 &> /dev/null [root@centos7 ~]# ping 172.25.67.47 -c3 &> /dev/null && echo the host is up the host is up
短路与中要特别注意的坑:
1注意expr命令
如果一个变量和一个数进行运算,值为0,那么返回值为非0,他认为是错误的。
在命令行输入man erpr 查看帮助文档:
Exit status(也就是$?) is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.
写脚本的时候不要作为条件判断的依据。
[root@centos7 ~]# y=9;expr $y - 9 0 [root@centos7 ~]# echo $? 1 [root@centos7 ~]# expr $x + 0 0 [root@centos7 ~]# echo $? 1 [root@centos7 ~]# z=6;expr $z + 0 6 [root@centos7 ~]# echo $? 0
2赋值特别容易出错的地方。
如果let后面跟的表达式的结果为0,那么他认为结果是错误的返回值就是非0了。
[root@centos7 ~]# i=0;let i++;echo $?先取i的值,i的值是0,返回的是假了,返回值就是非0了。 1 [root@centos7 ~]# i=0;let ++i;echo $?先进行自增,那么自增的结果就是非0了,返回的是真,返回值就是0了。 0[root@centos7 ~]# let j=0;echo $? 1
let命令是一个内部命令。
[root@centos7 ~]# type let let is a shell builtin [root@centos7 ~]# help l let local logout [root@centos7 ~]# help let let: let arg [arg ...] Evaluate arithmetic expressions. Evaluate each ARG as an arithmetic expression. Evaluation is done in fixed-width integers with no check for overflow, though division by 0 is trapped and flagged as an error. The following list of operators is grouped into levels of equal-precedence operators. The levels are listed in order of decreasing precedence. id++, id-- variable post-increment, post-decrement ++id, --id variable pre-increment, pre-decrement -, + unary minus, plus !, ~ logical and bitwise negation ** exponentiation *, /, % multiplication, division, remainder +, - addition, subtraction <<, >> left and right bitwise shifts <=, >=, <, > comparison ==, != equality, inequality & bitwise AND ^ bitwise XOR | bitwise OR && logical AND || logical OR expr ? expr : expr conditional operator =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= assignment Shell variables are allowed as operands. The name of the variable is replaced by its value (coerced to a fixed-width integer) within an expression. The variable need not have its integer attribute turned on to be used in an expression. Operators are evaluated in order of precedence. Sub-expressions in parentheses are evaluated first and may override the precedence rules above. Exit Status: If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.如果最后一个参数是0,那么返回值就是1了。否则返回值为0了。
应用在短路与中
[root@centos7 ~]# n=50
[root@centos7 ~]# m=-50
[root@centos7 ~]# let sum=n+m
[root@centos7 ~]# echo $?
1
[root@centos7 ~]# echo $?
0[root@centos7 ~]# let sum=n+m && echo $sum 短路与出现的问题,本来是应该打印出结果的值的
[root@centos7 ~]# let sum=n+m ; echo $sum不过可以使用分号隔开
0
2短路或
第一个为1,结果必定为1
第一个为0,第二个必须要参与运算
cmd1 短路或 cmd2
如果cmd1 为假,将执行cmd2
如果cmd1 为真,将不执行cmd2
真 1
假 0
真或假 有一个为真,结果为真
|| 代表条件性的OR ELSE,也就是短路或
[root@centos7 ~]# ping 172.25.67.48 -c3 -w1 &> /dev/null && echo the host is up || echo the host is down the host is down
如果ping通显示up,否则就显示down。
我们ping机器的时候ping不通,为假,那么就不会执行echo the host is up这个命令了。
因为假和任何数与都是假,那么ping 172.25.67.48 -c3 -w1 &> /dev/null && echo the host is up整体就为假了。
如果为假那么短路或就会执行后续的命令。所以就执行了 echo the host is down这条命令。
如果ping通了,那么ping 172.25.67.48 -c3 -w1就为真,就要执行echo the host is up。
因为echo会执行成功的,所以ping 172.25.67.48 -c3 -w1 &> /dev/null && echo the host is up整体上是真,那么短路或就不会执行了。
现在是根据不同的情况执行不同的命令了。
3异或:^
异或的两个值,相同为假,不同为真
异或:^
异或,英文为exclusive OR,缩写成xor。是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。
其运算法则为:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。异或的两个值,相同为假,不同为真。
异或的时候把两个值拆开成二进制,对位进行异或。
若x是二进制数0101,y是二进制数1011;
则x⊕y=1110
只有在两个比较的位不同时其结果是1,否则结果为0
即“两个输入相同时为0,不同则为1”!
现实中用的都是十进制的数值,那么我们来看一看两个十进制数值是怎么进行异或计算:
5 ⊕ 3 = ?
1.进行异或计算前会把数值都转换为二进制:
5和3转为二进制分别为:0101 、0011
2.再把结果 0110 转换为十进制的:6
3.所以 5 ⊕ 3 = 6
再比如十进制数30和40,转化为二进制数为00011110,00101000.
注意十进制的数转化成二进制是没有位数限制的,只有当规定用几个字节来表示的时候才用高位补充.
比如规定用一个字节来表示的时候,它是有取值范围的,这个数要小于256,
大于这个就不能表示了,在范围内高位用0补充.为了便于计算我使用了8位数。
把00110110转化为十进制数就是54.
3100使用异或可以直接把两个数对调。好处是不需要借助第三方了。
[root@centos7 ~]# a=5 [root@centos7 ~]# b=7 [root@centos7 ~]# a=$[a^b] [root@centos7 ~]# b=$[a^b] [root@centos7 ~]# a=$[a^b] [root@centos7 ~]# echo $a,$b 7,5
四条件测试
判断某需求是否满足,需要由测试机制来实现。
专用的测试表达式需要由测试命令辅助完成测试过程。
评估布尔声明,以便用在条件性执行中
• 若真,则返回0
• 若假,则返回1
测试命令:
• test EXPRESSION
• [ EXPRESSION ]
• [[ EXPRESSION ]]和上面两个不同的在于支持正则表达式
注意:EXPRESSION前后必须有空白字符
[root@centos7 ~]# type test test is a shell builtin [root@centos7 ~]# type [ [ is a shell builtin 内部命令 [root@centos7 ~]# type [[ [[ is a shell keyword关键字
比较两个字符串是否相同
[root@centos7 ~]# srtr1=abc [root@centos7 ~]# srtr2=abc [root@centos7 ~]# test str1=str2 [root@centos7 ~]# echo $? 0 [root@centos7 ~]# test str1 = str2 [root@centos7 ~]# echo $? 1 [root@centos7 ~]# srtr1=abc [root@centos7 ~]# srtr2=def [root@centos7 ~]# test str1 = str2 [root@centos7 ~]# echo $? 1
[root@centos7 ~]# test str1 != str2
[root@centos7 ~]# echo $?
0
[root@centos7 ~]# test str1 ! = str2
#注意!=一定要连在一起的
-bash: test: too many argumentsy
使用中括号。
系统里面的脚本也是使用中括号。
使用中括号好,因为test是字符串,容易和其他的字符串混在一起,而中括号一目了然。
[root@centos7 ~]# srtr1=abc [root@centos7 ~]# srtr2=abc [root@centos7 ~]# [test1 = test2] -bash: [test1: command not found
#使用中括号EXPRESSION前后必须有空白字符 [root@centos7 ~]# [ test1 = test2 ] [root@centos7 ~]# echo $? 0
系统里面的脚本也是使用中括号
[root@centos73 shell_scripts]# cat /etc/init.d/functions
# -*-Shell-script-*-
#
# functions This file contains functions to be used by most or all
# shell scripts in the /etc/init.d directory.
#
TEXTDOMAIN=initscripts
# Make sure umask is sane
umask 022
# Set up a default search path.
PATH="/sbin:/usr/sbin:/bin:/usr/bin"
export PATH
if [ $PPID -ne 1 -a -z "$SYSTEMCTL_SKIP_REDIRECT" ] &&
[ -d /run/systemd/system ] ; then
case "$0" in
/etc/init.d/*|/etc/rc.d/init.d/*)
_use_systemctl=1
;;
esac
fi
在中括号里面,只要中括号里面有东西就是为真,没有就是为假
[root@centos7 ~]# [ ] && echo true || echo false false [root@centos7 ~]# [ 123 ] && echo true || echo false true [root@centos7 ~]# [ 1243] && echo true || echo false -bash: [: missing `]' false [root@centos7 ~]# [1243] && echo true || echo false -bash: [1243]: command not found false [root@centos7 ~]# [1243 ] && echo true || echo false -bash: [1243: command not found false
?如果中括号里面是引号,就要空格
[root@centos7 ~]# [ "" ] && echo true || echo false
false
[root@centos7 ~]# [ " " ] && echo true || echo false
true
如果变量是有值,但是是空字符串,那么直接写就假,要使用引号引起来
[root@centos7 ~]# a=36 [root@centos7 ~]# [ $a ] && echo true || echo false true [root@centos7 ~]# unset a [root@centos7 ~]# a=" " [root@centos7 ~]# [ $a ] && echo true || echo false false [root@centos7 ~]# [ "$a" ] && echo true || echo false true
可以使用中括号判断某个变量是否赋值了
[root@centos7 ~]# [ "x"$a = "x" ] && echo true || echo false
#这个x纯粹就是为了组合的,x和字符串组合,如果a没有定义,那么x就等于x。这里的x是一个字母代表,使用其他的字母也可以。 true [root@centos7 ~]# a=245 [root@centos7 ~]# [ "x"$a = "x" ] && echo true || echo false false
在6里面的vim /etc/rc.sysinit中使用的就是这种方法。
645 # Start up swapping.
646 update_boot_stage RCswap
647 action $"Enabling /etc/fstab swaps: " swapon -a -e
648 if [ "$AUTOSWAP" = "yes" ]; then
649 curswap=$(awk '/^/dev/ { print $1 }' /proc/swaps | while read x; do get_numeric_dev dec $x ; echo -n " "; done)
650 swappartitions=$(blkid -t TYPE=swap -o device)
651 if [ x"$swappartitions" != x ]; then
652 for partition in $swappartitions ; do
653 [ ! -e $partition ] && continue
654 majmin=$(get_numeric_dev dec $partition)
655 echo $curswap | grep -qw "$majmin" || action $"Enabling local swap partitions: " swapon $partition