随堂练习 shell脚本(二)

算术运算

Shell允许在某些情况下对算术表达式进行求值,比如:let和declare 内置命令,(( ))复合命令和算术扩展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 被困并标记为错误。运算符及其优先级,关联性和值与C语言相同。以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。

注意:bash 只支持整数,不支持小数

id++ id--   variable post-increment and post-decrement
++id --id   variable pre-increment and pre-decrement
- +   unary minus and plus
! ~   logical and bitwise negation
**   exponentiation 乘方
* / %   multiplication, division, remainder, %表示取模,即取余数,示例:9%4=1,5%3=2
+ -   addition, subtraction
<< >> l  eft and right bitwise shifts
<= >= < >   comparison
== !=   equality and inequality
&   bitwise AND
^   bitwise exclusive OR
|   bitwise OR
&& l  ogical AND
||   logical OR
expr?expr:expr   conditional operator
= *= /= %= += -= <<= >>= &= ^= |=   assignment
expr1 , expr2   comma

乘法符号有些场景中需要转义
实现算术运算:

1)let var =算术表达式

2)((var=算术表达式))  和上面等价

3)var=$[算术表达式]

4)var=$((算术表达式))

5)var=$(expr arg1 arg2  ... )

6)declare -i var = 数值

7)echo '算术表达式' | bc

内建的随机数生成器变量:

$RANDOM   取值范围:0 - 32767

范例

#生成 0 - 49 之间随机数
echo $[$RANDOM%50]
# 随机字体颜色
[root@centos8 ~]# echo -e "33[1;$[RANDOM%7+31]hello33[0m"
hello

增强型赋值

+=  i+=10 相当于 i=i+10

-=  i-=j  相当于 i=i-j

*=

/=

%=

++ i++,++i   相当于  i=i+1

--  i--,--i    相当于 i=i-1

格式

let varOPERvalue

[root@centos8 ~]# let i=10*2
[root@centos8 ~]# echo $i
20
[root@centos8 ~]# ((j=i+10))
[root@centos8 ~]# echo $j
30

范例

#自加3后自赋值
let count+=3
[root@centos8 ~]# i=10
[root@centos8 ~]# let i+=20   #相当于let i=i+20
[root@centos8 ~]# echo $i
30
[root@centos8 ~]# j=20
[root@centos8 ~]# let i*=j
[root@centos8 ~]# echo $i

600

范例

#自增,自减
let var+=1
let var++
let var-=1
let var--
[root@centos8 ~]# unset i j ; i=1; let j=i++; echo "i=$i,j=$j"
i=2,j=1
[root@centos8 ~]# unset i j ; i=1; let j=++i; echo "i=$i,j=$j"
i=2,j=2

范例

[root@centos8 ~]# expr 2 * 3
expr: syntax error: unexpected argument ‘anaconda-ks.cfg’
[root@centos8 ~]# ls
anaconda-ks.cfg
[root@centos8 ~]# expr 2 * 3
6

范例

[root@centos8 ~]# echo "scale=3;20/3"|bc
6.666

范例

[root@centos8 ~]# i=10
[root@centos8 ~]# j=20
[root@centos8 ~]# declare -i result=i*j
[root@centos8 ~]# echo $result
200

范例:今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何?

#!/bin/bash

HEAD=$1

FOOT=$2

((RABBIT=(FOOT-HEAD-HEAD)/2))

((CHOOK=HEAD-RABBIT))

echo RABBIT: $RABBIT

echo CHOOK: $CHOOK

逻辑运算

1  true

0  false

与:&:和0相与,结果为0,和1相与,结果保留原值

1 与 1 = 1

1 与 0 = 0

0 与 1 = 0

0 与 0 = 0

或:|:和1相或结果为1,和0相或,结果保留原值

1 或 1 = 1

1 或 0 = 1

0 或 1 = 1

0 或 0 = 0

非:!

!1 = 0   !  true

! 0 = 1  !  false

异或:^
异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得出另一个值Y

1 ^ 1 = 0
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1

范例

[root@centos8 ~]# true
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# false
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# ! true
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# ! false
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# x=10;y=20;temp=$x;x=$y;y=$temp;echo x=$x,y=$y
x=20,y=10
[root@centos8 ~]# x=10;y=20;x=$[x^y];y=$[x^y];x=$[x^y];echo x=$x,y=$y
x=20,y=10

短路运算

短路与

CMD1 短路与 CMD2
第一个CMD1结果为真 (1),第二个CMD2必须要参与运算,才能得到最终的结果
第一个CMD1结果为假 (0),总的结果必定为0,因此不需要执行CMD2

短路或

CMD1 短路或 CMD2
第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,才能得到最终的结果

条件测试命令

条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成
测试过程
,实现评估布尔声明,以便用在条件性环境下进行执行
若真,则状态码变量 $? 返回0

若假,则状态码变量 $? 返回1

条件测试命令

  test EXPRESSION
  [ EXPRESSION ] #和test 等价,建议使用 [ ]
  [[ EXPRESSION ]]
注意:EXPRESSION前后必须有空白字符

变量测试

# 判断 NAME 变量是否定义
[ -v NAME ]
# 判断 NAME 变量是否定义并且是名称引用,bash 4.4新特性
[ -R NAME ]

范例

[root@centos8 ~]# unset x
[root@centos8 ~]# test -v x
[root@centos8 ~]# echo $?
1

[root@centos8 ~]# x=10
[root@centos8 ~]# test -v x
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# y=
[root@centos8 ~]# test -v y
[root@centos8 ~]# echo $?
0
#注意 [ ] 需要空格,否则会报下面错误
[root@centos8 ~]# [-v y]
-bash: [-v: command not found
[root@centos8 ~]# [ -v y ]
[root@centos8 ~]# echo $?
0

数值测试

-eq  是否等于

-ne  是否不等于

-gt  是否大于

-ge  是否大于等于

-lt   是否小于

-le   是否小于等于

范例

[root@centos8 ~]# i=10
[root@centos8 ~]# j=8
[root@centos8 ~]# [ $i -lt $j ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# [ $i -gt $j ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [ i -gt j ]
-bash: [: i: integer expression expected

算术表达式比较

<=
>=
<
>

范例

[root@centos8 ~]# x=10;y=20;(( x > y )); echo $?
1
[root@centos8 ~]# x=10;y=20;(( x < y )); echo $?
0

字符串测试

test 和 [ ] 用法

-z STRING 字符串是否为空,没定义或空为真,不空为假,

-n STRING 字符串是否不空,不空为真,空为假
STRING 同上

STRING1 = STRING2 是否等于,注意 = 前后有空格

STRING1 != STRING2 是否不等于

> ascii 码是否大于 ascii 码

< 是否小于

[[]] 用法

[[ expression ]] 用法
==   左侧字符串是否和右侧的PATTERN相同
     注意:此表达式用于[[ ]]中,PATTERN为通配符
=~   左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
     注意: 此表达式用于[[ ]]中;扩展的正则表达式

建议:当使用正则表达式或通配符使用[[ ]],其它情况一般使用 [ ]

范例 :使用 [ ]

[root@centos8 ~]# unset str
[root@centos8 ~]# [ -z "$str" ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# str=""
[root@centos8 ~]# [ -z "$str" ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# str=" "
[root@centos8 ~]# [ -z "$str" ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# [ -n "$str" ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# unset str
[root@centos8 ~]# [ -n "$str" ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# [ "$str" ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# str=magedu
[root@centos8 ~]# [ "$str" ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# str=magedu
[root@centos8 ~]# [ "$str" ]
[root@centos8 ~]# echo $?

0
[root@centos8 ~]# str1=magedu
[root@centos8 ~]# str2=mage
[root@centos8 ~]# [ $str1 = $str2 ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# str2=magedu
[root@centos8 ~]# [ $str1 = $str2 ]
[root@centos8 ~]# echo $?
0

范例:在比较字符串时,建议变量放在“ ”中

[root@centos8 ~]# [ "$NAME" ]
[root@centos8 ~]# NAME="I love linux"
[root@centos8 ~]# [ $NAME ]
-bash: [: love: binary operator expected
[root@centos8 ~]# [ "$NAME" ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [ I love linux ]
-bash: [: love: binary operator expected

范例:使用 [[ ]]

#通配符
[root@centos8 ~]# FILE=test.log
[root@centos8 ~]# [[ "$FILE" == *.log ]]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# FILE=test.txt
[root@centos8 ~]# [[ "$FILE" == *.log ]]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# [[ "$FILE" != *.log ]]
[root@centos8 ~]# echo $?
0
#正则表达式
[root@centos8 ~]# [[ "$FILE" =~ .log$ ]]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# FILE=test.log
[root@centos8 ~]# [[ "$FILE" =~ .log$ ]]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# N=100
[root@centos8 ~]# [[ "$N" =~ ^[0-9]+$ ]]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# N=Magedu10
[root@centos8 ~]# [[ "$N" =~ ^[0-9]+$ ]]
[root@centos8 ~]# echo $?
1

[root@centos8 ~]# IP=1.2.3.4
[root@centos8 ~]# [[ "$IP" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}$ ]]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# IP=1.2.3.4567
[root@centos8 ~]# [[ "$IP" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}$ ]]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# [[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3} ([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
[root@centos8 ~]# echo $?
1
#通配符
[root@centos8 ~]# NAME="linux1"
[root@centos8 ~]# [[ "$NAME" == linux* ]]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [[ "$NAME" == "linux*" ]]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# NAME="linux*"
[root@centos8 ~]# [[ "$NAME" == "linux*" ]]
[root@centos8 ~]# echo $?
0
# 结论:[[ == ]] == 右侧的 * 做为通配符,不要加“”,只想做为*, 需要加“” 或转义

文件测试

存在性测试

-a FILE  同 -e

-e FILE  文件存在性测试,存在为真,否则为假

-b FILE  是否存在且为块设备文件

-c FILE  是否存在且为字符设备文件

-d FILE  是否存在且为目录文件

-f FILE  是否存在且为普通文件

-h FILE 或 -L FILE  存在且为符号链接文件

-p FILE  是否存在且为命名管道文件

-s FILE  是否存在且为套接字文件

范例

[root@centos8 ~]# [ -a /etc/nologin ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# ! [ -a /etc/nologin ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [ -d /etc ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [ -d /etc/issue ]
[root@centos8 ~]# echo $?

1
[root@centos8 ~]# [ -L /bin ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [ -L /bin/ ]
[root@centos8 ~]# echo $?
1

文件权限测试

-r FILE  是否存在且可读

-w FILE  是否存在且可写

-x FILE  是否存在且可执行

-u FILE  是否存在且拥有 suid 权限

-g FILE  是否存在且拥有 sgid 权限

-k FILE  是否存在且拥有 Sticky 权限

注意:最终结果由用户对文件的实际权限决定,而非文件属性决定

范例

[root@centos8 ~]# [ -w /etc/shadow ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [ -x /etc/shadow ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# [ -w test.txt ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# chattr +i test.txt
[root@centos8 ~]# lsattr test.txt
----i-------------- nianling.txt
[root@centos8 ~]# [ -w test.txt ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# chattr -i test.txt
[root@centos8 ~]# [ -w test.txt ]
[root@centos8 ~]# echo $?
0

文件属性测试

-s FILE   #是否存在且非空
-t fd         #fd 文件描述符是否在某终端已经打开
-N FILE   #文件自从上一次被读取之后是否被修改过
-O FILE   #当前有效用户是否为文件属主
-G FILE   #当前有效用户是否为文件属组
FILE1 -ef FILE2   #FILE1是否是FILE2的硬链接
FILE1 -nt FILE2   #FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2   #FILE1是否旧于FILE2

关于 ()和 {}

(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行

[root@centos8 ~]# man bash

( list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境,帮助参看:man bash 搜索(list)
{ list; } 不会启子shell, 在当前shell中运行,会影响当前shell环境帮助参看:man bash 搜索{ list; }

范例: () 和 {}

[root@centos8 ~]# name=mage;(echo $name;name=wang;echo $name );echo $name
mage
wang
mage
[root@centos8 ~]# name=mage;{ echo $name;name=wang;echo $name; } ;echo $name
mage
wang
wang
[root@centos8 ~]# umask
0022
[root@centos8 ~]# (umask 066;touch f1.txt)
[root@centos8 ~]# ll f1.txt
-rw------- 1 root root 0 Dec 23 16:58 f1.txt
[root@centos8 ~]# umask
0022
[root@centos8 ~]# ( cd /data;ls )
test.log
[root@centos8 ~]# pwd
/root
[root@centos8 ~]# { cd /data;ls; }
test.log
[root@centos8 data]# pwd
/data

#()会开启子shell
[root@centos8 ~]# echo $BASHPID
1920
[root@centos8 ~]# ( echo $BASHPID;sleep 100)
1979
[root@centos8 ~]# pstree -p
├─sshd(719)───sshd(1906)───sshd(1919)─┬─bash(1920)───bash(1979)───sleep(1980)

#{ } 不会开启子shell
[root@centos8 ~]# echo $BASHPID
1920
[root@centos8 ~]# { echo $BASHPID; }
1920

组合测试条件

第一种方式 [ ]

[ EXPRESSION1 -a EXPRESSION2 ] 并且,EXPRESSION1和EXPRESSION2都是真,结果才为真
[ EXPRESSION1 -o EXPRESSION2 ] 或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为真
[ ! EXPRESSION ]   取反

说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持

范例

[root@centos8 ~]# ll /data/scrips/test.sh
-rw-r--r-- 1 root root 382 Dec 23 09:32 /data/scripts/test.sh
[root@centos8 ~]# [ -f $FILE -a -x $FILE ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# chmod +x /data/scripts/test.sh
[root@centos8 ~]# ll /data/scripts/test.sh
-rwxr-xr-x 1 root root 382 Dec 23 09:32 /data/script40/test.sh
[root@centos8 ~]# [ -f $FILE -a -x $FILE ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# chmod -x /data/scripts/test.sh
[root@centos8 ~]# ll /data/scripts/test.sh
-rw-r--r-- 1 root root 382 Dec 23 09:32 /data/scripts/test.sh
[root@centos8 ~]# [ -f $FILE -o -x $FILE ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# [ -x $FILE ]
[root@centos8 ~]# echo $?
1
[root@centos8 ~]# [ ! -x $FILE ]
[root@centos8 ~]# echo $?
0
[root@centos8 ~]# ! [ -x $FILE ]
0

第二种方式

COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND   #非,取反

[root@centos7 ~]# [ $[RANDOM%6] -eq 0 ] && rm -rf /* || echo "click"click

范例

[root@centos8 ~]# test "A" = "B" && echo "Strings are equal"
[root@centos8 ~]# test "A"-eq "B" && echo "Integers are equal"
[root@centos8 ~]# [ "A" = "B" ] && echo "Strings are equal"
[root@centos8 ~]# [ "$A" -eq "$B" ] && echo "Integers are equal"
[root@centos8 ~]# [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
[root@centos8 ~]# [ -z "$HOSTNAME" -o "$HOSTNAME" = "localhost.localdomain" ]&& hostname www.longwang.com
[root@centos8 ~]# id wang &> /dev/null || useradd wang
[root@centos8 ~]# id zhang &> /dev/null || useradd zhang
[root@centos8 ~]# getent passwd zhang
zhang:x:1002:1002::/home/zhang:/bin/bash
[root@centos8 ~]# grep -q no_such_user /etc/passwd || echo 'No such user'
No such user

范例

[root@centos8 ~]# [ -f “$FILE” ] && [[ “$FILE”=~ .*.sh$ ]] && chmod +x $FILE
[root@centos8 ~]# ping -c1 -W1 172.16.0.1 &> /dev/null && echo '172.16.0.1 is up' || (echo '172.16.0.1 is unreachable'; exit 1)
172.16.0.1 is up
[root@centos8 ~]# IP=10.0.0.111;ping -c1 -W1 $IP &> /dev/null && echo $IP is up || echo $IP is down
10.0.0.111 is down
[root@centos8 ~]# IP=10.0.0.1;ping -c1 -W1 $IP &> /dev/null && echo $IP is up || echo $IP is down
10.0.0.1 is up

范例:&& 和 || 组合使用

[root@centos8 ~]# NAME=wang; id $NAME &> /dev/null && echo "$NAME is exist"
wang is exist
[root@centos8 ~]# NAME=wange; id $NAME &> /dev/null || echo "$NAME is not exist"
wange is not exist
[root@centos8 ~]# NAME=wange; id $NAME &> /dev/null && echo "$NAME is exist" || echo "$NAME is not exist"
wange is not exist
[root@centos8 ~]# NAME=wang; id $NAME &> /dev/null && echo "$NAME is exist" || echo "$NAME is not exist"
wang is exist
[root@centos8 ~]# NAME=wang; id $NAME &> /dev/null && echo "$NAME is exist" || echo "$NAME is not exist"
wang is exist
[root@centos8 ~]# NAME=wang; id $NAME &> /dev/null || echo "$NAME is not exist" && echo "$NAME is exist"
wang is exist

[root@centos8 ~]# NAME=wange; id $NAME &> /dev/null || echo "$NAME is not exist" && echo "$NAME is exist"
wange is not exist
wange is exist

# 结论:如果&& 和 || 混合使用,&& 要在前,|| 放在后

[root@centos8 ~]# NAME=wange; id $NAME &> /dev/null && echo "$NAME is exist" || useradd $NAME
[root@centos8 ~]# id wange
uid=1002(wange) gid=1002(wange) groups=1002(wange)
[root@centos8 ~]# NAME=wangge; id $NAME &> /dev/null && echo "$NAME is exist" || ( useradd $NAME; echo $NAME is created )
wangge is created
[root@centos8 ~]# id wangge
uid=1003(wangge) gid=1003(wangge) groups=1003(wangge)
[root@centos8 ~]# NAME=wanggege; id $NAME &> /dev/null && echo "$NAME is exist" || { useradd $NAME; echo $NAME is created; }
wanggege is created

范例:网络状态判断

#!/bin/bash

IP=10.0.0.100

ping -c1 -W1 $IP &> /dev/null && echo "$IP is up" || { echo "$IP is unreachable"; exit; }

echo "Script is finished"

范例:磁盘空间的判断

#!/bin/bash

WARNING=80

SPACE_USED=`df|grep '^/dev/sd'|tr -s ' ' % | cut -d% -f5 | sort -nr | head -n1`

[ "$SPACE_USED" -ge $WARNING ] && echo "disk used is $SPACE_USED,will be full" | mail -s diskwaring root

范例:磁盘空间和Inode号的检查脚本

#!/bin/bash

WARNING=80

SPACE_USED=`df | grep '^/dev/sd' | grep -Eo '[0-9]+%' |tr -d % | sort -nr | head -n1`

INODE_USED=`df -i |grep '^/dev/sd' |grep -Eo '[0-9]+%' | tr -d % | sort -nr | head -n1`

[ "$SPACE_USED" -gt  $WARNING -o "$INODE_USED" -gt $WARNING ] && echo "DISK USED:$SPACE_USED%,INODE_USED:$INODE_USED,will be full" | mail -s "DISK Warning" root@llxuan0360@163.com

原文地址:https://www.cnblogs.com/xuanlv-0413/p/13225172.html