[华为云在线课程][Shell脚本编程基础][第二章Shell脚本语言的基本用法][3算术运算及测试][学习笔记]

举报
John2021 发表于 2022/04/15 16:58:24 2022/04/15
【摘要】 格式化输出printf格式printf "指定的格式" "文本1" "文本2"......常用格式替换符%s 字符串%f 浮点格式%b 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义%c ASCII字符,即显示对应参数的第一个字符%d,%i 十进...

格式化输出printf

格式

printf "指定的格式" "文本1" "文本2"......

常用格式替换符

%s             字符串
%f             浮点格式
%b             相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义
%c             ASCII字符,即显示对应参数的第一个字符
%d,%i          十进制整数
%o             八进制值
%u             不带正负号的十进制值
%x             十六进制(a-f)
%X             十六进制(A-F%%             表示%本身

说明:%#s中的#数字代表此替换符中的输出字符宽度,不足补空格,默认是右对齐,%-10s表示10个字符宽,-表示左对齐
常用转义字符

\a             警告字符,通常为ASCIIBEL字符
\b             后退
\f             换页
\n             换行
\r             回车
\t             水平制表符
\v             垂直制表符
\              表示\本身

例子:

[root@localhost Code]# printf '%s\n' 1 2 3 4
1
2
3
4
[root@localhost Code]# printf '%f\n' 1 2 3 4
1.000000
2.000000
3.000000
4.000000
[root@localhost Code]# printf '%.2f\n' 1 2 3 4
1.00
2.00
3.00
4.00
[root@localhost Code]# printf '(%s)' 1 2 3 4;echo
(1)(2)(3)(4)
[root@localhost Code]# printf ' (%s) ' 1 2 3 4;echo
 (1)  (2)  (3)  (4)
[root@localhost Code]# printf ' (%s) \n' 1 2 3 4;echo
 (1)
 (2)
 (3)
 (4)
[root@localhost Code]# printf '%s %s\n' 1 2 3 4
1 2
3 4
[root@localhost Code]# printf '%s %s %s\n' 1 2 3 4
1 2 3
4
#%-10s 表示宽度10个字符,左对齐
[root@localhost Code]# printf "%-10s %-10s %-4s %s \n" 姓名 性别 年龄 体重 小明 男 20 70 小红 女 18 50
姓名     性别     年龄 体重
小明     男        20   70
小红     女        18   50
#将十进制的17转换成16进制数
[root@localhost Code]# printf "%X" 17;echo
11
#将十六进制C转换为十进制
[root@localhost Code]# printf "%d\n" 0xC
12
[root@localhost Code]# VAR="Hello World";printf "\033[31m%s\033[0m\n" $VAR
Hello
World
[root@localhost Code]# VAR="Hello World";printf "\033[31m%s\033[0m\n" "$VAR"
Hello World

算术运算

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

* / %          multiplication,division,remainder,%表示取模,即取余数
+ -            addition,subtraction
i++ i--        variable post-increment and post-decrement
++i --i        variable pre-increment and post-increment
= *= /= %= += -= <<= >>= &= ^= |=    assignment
- +            unary minus and plus
! ~            logical and bitwise negation
**             exponentiation
<< >>          left and right bitwise shifts
<= >= < >      comparison
== !=          equality and inequality
&              bitwise AND
|              bitwise OR
^              bitwise exclusive OR
&&             logical AND
||             logical OR
expr?expr:expr      conditional operator
expr1,expr2    comma

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

1let var=算术表达式
(2)((var=算术表达式)) 和上面等价
(3var=$[算术表达式]4var=$((算术表达式))5var=$(expr arg1 arg2 arg3 ...)6)declare -i var=数值
(7)echo '算术表达式' | bc

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

$RANDOM 取值范围:0-32767

例子:

#生成 0-49 之间随机数
echo $[$RANDOM%50]

#随机字体颜色
[root@localhost Code]# echo -e "\033[1;$[RANDOM%7+31]m  hello  \033[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@localhost Code]# let i=10*2
[root@localhost Code]# echo $i
20
[root@localhost Code]# ((j=i+10))
[root@localhost Code]# echo $j
30

例子:

#自加3后赋值
[root@localhost Code]# let count+=3
[root@localhost Code]# i=10
[root@localhost Code]# let i+=20
[root@localhost Code]# echo $i
30
[root@localhost Code]# j=20
[root@localhost Code]# let i*=j
[root@localhost Code]# echo $i
600

例子:

#自增,自减
[root@localhost Code]# unset i j;i=1;let j=i++;echo "i=$i,j=$j"
i=2,j=1
[root@localhost Code]# unset i j;i=1;let j=++i;echo "i=$i,j=$j"
i=2,j=2

例子:

[root@localhost Code]# expr 2 *3
expr: syntax error
[root@localhost Code]# expr 2\* 3
expr: syntax error
[root@localhost Code]# expr 2 \* 3
6

例子:

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

例子:

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

例子:计算鸡兔同笼,上有35头,下有94脚,问鸡兔各有多少只?

[root@localhost Code]# cat chook_rabbit.sh
#!/bin/bash

HEAD=$1
FOOT=$2

RABBIT=$(((FOOT-HEAD-HEAD)/2))
CHOOK=$[HEAD-RABBIT]
echo RABBIT:$RABBIT
echo CHOOK:$CHOOK

[root@localhost Code]# ./chook_rabbit.sh 35 94
RABBIT:12
CHOOK:23

逻辑运算

true,false

1,真
0,假
#注意,以上为二进制

&(与):与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异或得到结果ZZ再和任意两者之一X异或,将得出另一个值Y
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

例子:

[root@localhost Code]# true
[root@localhost Code]# echo $?
0
[root@localhost Code]# false
[root@localhost Code]# echo $?
1
[root@localhost Code]# !true
true
[root@localhost Code]# ! true
[root@localhost Code]# echo $?
1
[root@localhost Code]# ! false
[root@localhost Code]# echo $?
0

例子:变量互换

[root@localhost Code]# x=10;y=20;temp=$x;x=$y;y=$temp;echo x=$x,y=$y
x=20,y=10
[root@localhost Code]# 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前后必须有空白字符
帮助:

[root@localhost Code]# type [
[ is a shell builtin

[root@localhost Code]# help [
[: [ arg... ]
    Evaluate conditional expression.

    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.
[[ ... ]]: [[ expression ]]
    Execute conditional command.

[root@localhost Code]# help test
test: test [expr]
    Evaluate conditional expression.

    Exits with a status of 0 (true) or 1 (false) depending on
    the evaluation of EXPR.  Expressions may be unary or binary.  Unary
    expressions are often used to examine the status of a file.  There
    are string operators and numeric comparison operators as well.

    The behavior of test depends on the number of arguments.  Read the
    bash manual page for the complete specification.

变量测试

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

例子:

[root@localhost Code]# unset x
[root@localhost Code]# test -v x
[root@localhost Code]# echo $?
1
[root@localhost Code]# unset x
[root@localhost Code]# echo $?
0
[root@localhost Code]# x=10
[root@localhost Code]# test -v x
[root@localhost Code]# echo $?
0

[root@localhost Code]# test -v y | echo $?
0

#注意[ ]需要空格,否则会报下面错误
[root@localhost Code]# [-v y]
-bash: [-v: command not found
[root@localhost Code]# [ -v y]
-bash: [: missing `]'
[root@localhost Code]# [ -v y ]
[root@localhost Code]# echo $?
0

数值测试

-eq         是否等于
-ne         是否不等于
-gt         是否大于
-ge         是否大于等于
-lt         是否小于
-le         是否小于等于

例子:

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

算术表达式比较

==
!=
<=
>=
<
>

例子:

[root@localhost Code]# x=10;y=10;((x==y));echo $?
0
[root@localhost Code]# x=10;y=20;((x==y));echo $?
1
[root@localhost Code]# x=10;y=20;((x!=y));echo $?
0
[root@localhost Code]# x=10;y=10;((x!=y));echo $?
1

例子:

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

字符串测试

test和[]用法

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

STRING1 = STRING2   是否等于,注意=前后有空格
STRING1 != STRING2  是否不等于
>                 ASCII码是否大于ASCII<                 ASCII码是否小于ASCII

[[]]用法

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

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

[root@localhost Code]# unset str
[root@localhost Code]# [ -z "$str" ]
[root@localhost Code]# echo $?
0
[root@localhost Code]# str=""
[root@localhost Code]# [ -z "$str" ]
[root@localhost Code]# echo $?
0
[root@localhost Code]# str=" "
[root@localhost Code]# [ -z "$str" ]
[root@localhost Code]# echo $?
1
[root@localhost Code]# [ -z "$str" ]
[root@localhost Code]# echo $?
1
[root@localhost Code]# [ "$str" ]
[root@localhost Code]# echo $?
0

[root@localhost Code]# str1=hello
[root@localhost Code]# str2=world
[root@localhost Code]# [ $str1 = $str2 ]
[root@localhost Code]# echo $?
1
[root@localhost Code]# str2=hello
[root@localhost Code]# [ $str1 = $str2 ]
[root@localhost Code]# echo $?
0

例子:在比较字符串时,建议变量放在""中

[root@localhost Code]# NAME="I love Linux"
[root@localhost Code]# [ $NAME ]
-bash: [: love: binary operator expected
[root@localhost Code]# [ "$NAME" ]
[root@localhost Code]# echo $?
0
[root@localhost Code]# [ I love Linux ]
-bash: [: love: binary operator expected

例子:[[]]和通配符

[root@localhost Code]# FILE="a*"
[root@localhost Code]# echo $FILE
arg.sh a.sh
[root@localhost Code]# [[ $FILE==a* ]]
[root@localhost Code]# echo $?
0
[root@localhost Code]# FILE="ab"
[root@localhost Code]# [[ $FILE==a* ]]
[root@localhost Code]# echo $?
0

#[[]]中如果不想使用通配符*,只想表达*本身,可以用" "引起来,也可以使用转义符
[root@localhost Code]# [[ FILE == a"*" ]]
[root@localhost Code]# echo $?
1
[root@localhost Code]# [[ FILE == a\* ]]
[root@localhost Code]# echo $?
1

#通配符?
[root@localhost Code]# FILE=abc
[root@localhost Code]# [[ $FILE == ??? ]]
[root@localhost Code]# echo $?
0
[root@localhost Code]# FILE=abcd
[root@localhost Code]# [[ $FILE == ??? ]]
[root@localhost Code]# echo $?
1

#通配符
[root@localhost Code]# NAME="linux"
[root@localhost Code]# [[ "$NAME" == linux* ]]
[root@localhost Code]# echo $?
0
[root@localhost Code]# [[ "$NAME" == "linux*" ]]
[root@localhost Code]# echo $?
1
[root@localhost Code]# NAME="linux*"
[root@localhost Code]# [[ "$NAME" == "linux*" ]]
[root@localhost Code]# echo $?
0
#结论:[[ == ]] == 右侧的 * 作为通配符,不要加"",只想作为*,需要加""或者转义

例子:判断合理的考试成绩

[root@localhost Code]# SCORE=101
[root@localhost Code]# [[ $SCORE =~ 100|[0-9]{1,2}  ]]
[root@localhost Code]# echo $?
0
[root@localhost Code]# [[ $SCORE =~ ^(100|[0-9]{1,2})$  ]]
[root@localhost Code]# echo $?
1
[root@localhost Code]# SCORE=10
[root@localhost Code]# [[ $SCORE =~ ^(100|[0-9]{1,2})$  ]]
[root@localhost Code]# echo $?
0
[root@localhost Code]# SCORE=abc
[root@localhost Code]# [[ $SCORE =~ ^(100|[0-9]{1,2})$  ]]
[root@localhost Code]# echo $?
1

文件测试

存在性测试

-a FILE-e
-e FILE         文件存在性测试,存在为真,否则为假
-b FILE         是否存在且为块设备文件
-c FILE         是否存在且为字符设备文件
-d FILE         是否存在且为目录文件
-f FILE         是否存在且为普通文件
-h FILE-L FILE 是否存在且为符号链接文件
-p FILE         是否存在且为命名管道文件
-s FILE         是否存在且为套接字文件

例子:

#文件是否存在
[root@localhost Code]# [ -a /home/hello/Code/hello ]
[root@localhost Code]# echo $?
1
[root@localhost Code]# [ -a /home/hello/Code/a.sh ]
[root@localhost Code]# echo $?
0

文件权限测试:

-r FILE         是否存在且可读
-w FILE         是否存在且可写
-x FILE         是否存在且可执行
-u FILE         是否存在且拥有suid权限
-g FILE         是否存在且拥有sgid权限
-k FILE         是否存在且拥有sticky权限

注意:最终结果由用户对文件的实际权限决定,而非文件属性决定。
例如将写权限关闭,但是root用户还是能执行操作。  

文件属性测试

-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;…;} 都可以将多个命令组合在一起,批量执行

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

组合测试条件

第一种方式 []

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

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

第二种方式

COMMAND1 && COMMAND2        并且,短路与,代表条件性的AND THEN
如果COMMAND1成功,将执行COMMAND2,否则,将不执行COMMAND2

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

注意:如果&&||混合使用,&&要在前,||要在后
#Linux版俄罗斯轮盘
[ $[RANDOM%6] -eq 0 ] && rm -rf /* || echo "You are lucky"

使用read命令来接受输入

使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量,如果变量名没有指定,默认标准输入的值赋值给系统内置变量REPLY
格式:

read [options] [name,...]

常见选项:

-p              指定要显示的提示
-s              静默输入,一般用于密码
-n N            指定输入的字符长度N
-d '字符'        输入结束符

例子:

[root@localhost Code]# read x y z <<< "I love you"
[root@localhost Code]# echo $x
I
[root@localhost Code]# echo $y
love
[root@localhost Code]# echo $z
you

例子:判断用户输入的是否为YES

[root@localhost Code]# cat yesorno.sh
#!/bin/bash

read -p "Please input yes or no: " input
answer=`echo $input|tr 'A-Z' 'a-z'`

[ $answer = 'yes' -o $answer = 'y' ] && echo YES
[ $answer = 'no' -o $answer = 'n'  ] && echo NO
[root@localhost Code]# cat yesorno2.sh
#!/bin/bash

read -p "Please input yes or no: " input

[[ $input =~ ^([Yy][Ee][Ss]|[Yy])$ ]] && echo YES
[[ $input =~ ^([Nn][Oo]|[Nn])$ ]]  && echo NO
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。