格式化输出、运算符以及read输入
- 格式化输出 printf
- 运算符
- 算术运算符
- 逻辑运算符
- 数值测试
- 字符串测试
- 文件测试
- 组合测试
格式化输出 printf
格式
printf \"指定格式\" \"文本1\" \"文本2\"
常用格式替换符
%s 以字符串形式输出%f 以浮点格式输出%b 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义 ?%c ASCII字符,即显示对应参数的第一个字符%d,%i 十进制整数%o 八进制值%u 不带正负号的十进制值%x 十六进制值(a-f),%X 表示十六进制的A-F%% 表示% 本身常用转义字符\\a 警告字符\\b 后退\\f 换页\\n 换行\\r 回车\\t 水平制表符\\v 垂直制表符\\ \\ 本身
%#s
中的# 是数字代表此替换符中的输出字符宽度,不足不空格,默认是右对齐。eg:%-10s 表示10个字符宽,- 表示左对齐
范例
#.2f 保留两位小数,且换行输出[root@CentOS8 ~]#printf \"%.2f\\n\" 1 2 31.002.003.00#将文本加()输出[root@CentOS8 ~]#printf \"(%s) \" 1 2 3;echo \'\'(1) (2) (3)[root@CentOS8 ~]#printf \"(%s)\\n\" 1 2 3(1)(2)(3)[root@CentOS8 ~]#printf \"%s %s\\n\" 1 2 3 41 23 4[root@CentOS8 ~]#printf \"%s %s %s\\n\" 1 2 3 41 2 34#制表,表格形式输出[root@CentOS8 ~]#printf \"%-10s %-10s %-4s %s \\n\" 姓名 性别 年龄 体重 小明 男 20 70 小花 女 19 50姓名 性别 年龄 体重小明 男 20 70小花 女 19 50#变量加引号和不加引号的区别#不加引号,将变量中的内容视为一个个的独立字符串[root@CentOS8 ~]#VAR=\"what is it?\";printf \"\\033[1;31m%s\\033[0m\\n\" $VARwhatisit?#加引号,将变量中的内容视为整体[root@CentOS8 ~]#VAR=\"what is it?\";printf \"\\033[1;31m%s\\033[0m\\n\" \"$VAR\"what is it?
运算符
算术运算符
shell 允许在某些情况下对算术表达式进行求值,如:let 和declare 内置命令, (( )) 复合命令和算术扩展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 并不被标记为错误?运算符及其优先级,关联性和C 语言相同。
注意:bash 只支持整数,不支持小数。且乘法符号在某些场景需转义
+ - * / % 加,减,乘,除,取模i++ i-- 先使用变量,再加1++i --i 先加1,再使用变量** 乘方<< >> 左移位 右移位+= -= *= /= %= <<= >>= &= ^= |= 增强型赋值 eg: a+=2 等同于 a=a+2,其他类似! ~ 非- + 正负值<= >= < > == != 比较运算符& 位与| 位或^ 位异或&& 逻辑与|| 逻辑或expr?expr:expr 三元表达式 ? 左边的expr是表达式,右边的expr是表达式为true 的值,: 后接的expr 是表达式为false 的值
实现算术运算
let var=算术表达式((var=算术表达式))var=$[算术表达式]var=$((算术表达式))var=$(expr arg1 arg2...)declare -i var = 数值echo \'算术表达式\' | bc
范例
[root@CentOS8 ~]#i=10[root@CentOS8 ~]#let i+=20[root@CentOS8 ~]#echo $i30[root@CentOS8 ~]#j=20[root@CentOS8 ~]#let i*=j[root@CentOS8 ~]#echo $i600[root@CentOS8 ~]#unset i j;[root@CentOS8 ~]#i=10[root@CentOS8 ~]#j=20[root@CentOS8 ~]#declare -i result=i*j[root@CentOS8 ~]#echo $result200[root@CentOS8 ~]#echo \"scale=3;20/3\" | bc6.666#自增,i++和++i 的区别[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 script]#vim chook_rabbit.sh1 #!/bin/bash2 #********************************************************************3 # Author:dawn4 # Date:2020-08-08 15:38:195 # FileName:chook_rabbit.sh6 # URL:https://blog.csdn.net/xiao_dan_7 # Version:1.08 # Description:The test script9 #********************************************************************10 HEAD=$111 FOOT=$21213 RABBIT=$(((FOOT-HEAD-HEAD)/2))14 CHOOK=$[HEAD-RABBIT]15 echo RABBIT:$RABBIT16 echo CHOOK:$CHOOK[root@CentOS8 script]#bash chook_rabbit.sh 30 80RABBIT:10CHOOK:20
逻辑运算符
true,false
1,真0,假
& 位与,和0相与,结果为0,和1相与,结果保留原值
1 & 1 = 11 & 0 = 00 & 1 = 00 & 0 = 0
| 位或,和1相或结果为1, 和0相或,结果保留原值
1 | 1 = 11 | 0 = 10 | 1 = 10 | 0 = 0
! 非
!1 = 0 !true!0 = 1 !false
^ 异或
异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得出另一个值Y
1 ^ 1 = 01 ^ 0 = 10 ^ 1 = 10 ^ 0 = 0
范例
#异或用于两个值之间的交换[root@CentOS8 script]#x=10;y=20;temp=$x;x=$y;y=$temp;echo x=$x,y=$yx=20,y=10[root@CentOS8 script]#x=10;y=20;x=$[x^y];y=$[x^y];x=$[x^y];echo x=$x,y=$yx=20,y=10
短路运算
&& 短路与
CMD1 短路与 CMD2第一个CMD1 结果为真(1), 第二个CMD2 必须参与运算,才能得到最终的结果第一个CMD1 结果为假(0),总的结果必定为0,因此不需要执行CMD2
|| 短路或
CMD1 短路或 CMD2第一个CMD1 结果为真(1),总的结果必定为1,因此不需要执行CMD2第一个CMD1 结果为假(0),第二个CMD2 必须参与运算,才能得到最终的结果
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字
-eq 检测两个数是否相等,相等返回true-ne 检测两个数是否不想等,不想等返回true-gt 是否大于,是返回true-ge 是否大于等于与,是返回true-lt 是否小于,是返回true-le 是否小于等于,是返回true
范例
[root@CentOS8 script]#i=10[root@CentOS8 script]#j=8[root@CentOS8 script]#[ $i -lt $j ][root@CentOS8 script]#echo $?1[root@CentOS8 script]#[ i -gt j ]-bash: [: i: integer expression expected
条件测试命令
判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成测试过程,实现评估布尔声明,以便用在条件性环境下进行执行
若真,则状态码变量?返回0若假,则状态码变量? 返回0若假,则状态码变量?返回0若假,则状态码变量? 返回1
数值测试
test EXPRESSION[ EXPRESSION ] 和test等价,建议使用[][[ EXPRESSION ]]ps:EXPRESSION 前后必须有空白字符#判断NAME 变量是否定义[ -v NAME ]#判断NAME 变量是否定义且是名称引用[ -R NAME ]
范例
[root@CentOS8 script]#unset x[root@CentOS8 script]#test -v x[root@CentOS8 script]#echo $?1#[ ] 内部必须有空格,否则无效[root@CentOS8 script]#[-v y]-bash: [-v: command not found[root@CentOS8 script]#[ -v y ][root@CentOS8 script]#echo $?0
字符串测试
test和[ ] 用法-z STRING 字符串是否为空,没定义或空则为真,不空为假-n STRING 字符串是否不空,不空则为真,空为假STRING 等同于 -n STRING[[ expression ]]用法== 左侧字符串是否和右侧的PATTERN相同此表达式用于[[ ]]中,PATTERN 为通配符=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配此表达式用于[[ ]]中,扩展的正则表达式
建议:当时用正则表达式或通配符使用[[]],其他情况一般使用[]
范例- [] 的使用
[root@CentOS8 script]#[ \"$NAME\" ][root@CentOS8 script]#echo $?1#比较字符串时,建议变量放在\"\" 中[root@CentOS8 script]#NAME=\"I love linux\"[root@CentOS8 script]#[ $NAME ]-bash: [: love: binary operator expected[root@CentOS8 script]#[ \"$NAME\" ][root@CentOS8 script]#echo $?0#比较字符串时,建议变量放在\"\" 中[root@CentOS8 script]#[ \"I love shell\" ][root@CentOS8 script]#echo $?0[root@CentOS8 script]#[ I love bash ]-bash: [: love: binary operator expected[root@CentOS8 script]#FILE=\"a*\"[root@CentOS8 script]#echo $FILEargs.sh a.sh[root@CentOS8 script]#echo \"$FILE\"a*
范例-[[]] 和通配符
[root@CentOS8 script]#FILE=\"ab\"[root@CentOS8 script]#[[ $FILE == a* ]][root@CentOS8 script]#echo $?0#加引号[root@CentOS8 script]#FILE=\"a*\"[root@CentOS8 script]#[[ $FILE == a\"*\" ]][root@CentOS8 script]#echo $?0#不想使用通配符*,而是想要表达*本身,可用\"\"引起来或者使用转义[root@CentOS8 script]#FILE=\"ab\"[root@CentOS8 script]#[[ $FILE == a\"*\" ]][root@CentOS8 script]#echo $?1[root@CentOS8 script]#[[ $FILE == a\\* ]][root@CentOS8 script]#echo $?1
范例-[[]] 和正则表达式
#判断文件后缀#方式1 通配符[root@CentOS8 ~]#FILE=test.txt[root@CentOS8 ~]#[[ \"$FILE\" == *.log ]][root@CentOS8 ~]#echo $?1#方式2 正则表达式[root@CentOS8 ~]#[[ \"$FILE\" =~ \\.log$ ]][root@CentOS8 ~]#echo $?1[root@CentOS8 ~]#FILE=test.log[root@CentOS8 ~]#[[ \"$FILE\" =~ \\.log$ ]][root@CentOS8 ~]#echo $?0
文件测试
存在性测试
-a FILE 同 -e-e FILE 文件存在性测试,存在为真,否为假-b FILE 是否存在且为块设备文件-c FILE 是否存在且为字符设备文件-d FILE 是否存在且为目录文件-f FILE 是否存在且为普通文件-h FILE 同 -L 是否存在且为符号链接文件-p FILE 是否存在且为管道文件-S FILE 是否存在且为套接字文件
文件权限测试
-r FILE 是否存在且可读-w FILE 是否存在且可写-x FILE 是否存在且可执行-u FILE 是否存在且拥有suid 权限-g FILE 是否存在且拥有sgid 权限-k FILE 是否存在且拥有sticky 权限
注意:最终结果由用户对文件的实际权限决定,而非文件属性决定
文件属性测试
-s FILE 是否存在且非空-t fd fd 文件描述符是否在某终端已经打开-N FILE 文件自从上一次被读取之后是否被修改过-O FILE 当前有效用户是否为文件属主-G FILE 当前有效用户是否为文件属组FILE1 -ef FILE2 FILE1s是否是FILE2的硬链接FILE1 -nt FILE2 FILE1s是否新于FILE2(mtime)FILE1 -ot FILE2 FILE1s是否旧于FILE2
组合测试
方式一 []
[ expre1 -a expre2 ] 且,expre1 和expre2 都为真,结果为真[ expre1 -o expre2 ] 或,expre1 和expre2 任意一个为真,结果为真[ ! expre ] 取反
注意:-a 和-o 需要使用测试命令进行,[[ ]] 不支持
范例
[root@CentOS8 ~]#ll /data/scripts/test.sh-rw-r--r-- 1 root root 0 Aug 11 10:03 /data/scripts/test.sh[root@CentOS8 ~]#FILE=\"/data/scripts/test.sh\"[root@CentOS8 ~]#[ -f $FILE -a -x $FILE ][root@CentOS8 ~]#echo $?1[root@CentOS8 ~]#[ -f $FILE -o -x $FILE ][root@CentOS8 ~]#echo $?0[root@CentOS8 ~]#[ ! -x $FILE ][root@CentOS8 ~]#echo $?0
方式二 && 和 ||
cmd1 && cmd2 且,短路与,表示条件性的and then如果cmd1 执行成功,将执行cmd2,否则,不执行cmd2cmd1 || cmd2 或,短路或,表示条件性的or else如果cmd1 执行成功,不执行cmd2,否则,将执行cmd2!cmd 非,取反
范例
[root@CentOS8 ~]#[ \"A\" = \"B\" ] && echo \"String are equal\"[root@CentOS8 ~]#[ \"A\" != \"B\" ] && echo \"String are equal\"String are equal[root@CentOS8 ~]#id haha &> /dev/null || useradd haha[root@CentOS8 ~]#getent passwd hahahaha:x:1001:1001::/home/haha:/bin/bash#&& 和|| 组合使用[root@CentOS8 ~]#name=dawn;id $name &> /dev/null && echo \"$name is exist\"dawn is exist[root@CentOS8 ~]#name=haha;id $name &> /dev/null || echo \"$name is not exist\"haha is not exist[root@CentOS8 ~]#name=dawn;id $name &> /dev/null && echo \"$name is exist\" || echo \"$name is not exist\"dawn is exist[root@CentOS8 ~]#name=dawn;id $name &> /dev/null || echo \"$name is exist\" && echo \"$name is not exist\"dawn is not exist[root@CentOS8 ~]#name=haha;id $name &> /dev/null || echo \"$name is exist\" && echo \"$name is not exist\"haha is existhaha is not exist[root@CentOS8 ~]#name=haha;id $name &> /dev/null && echo \"$name is exist\" || echo \"$name is not exist\"haha is not exist#总结:如果&& 和|| 混合使用,&& 要在前,|| 放在后
接受输入 read
使用 read 接收输入的值,将输入值分配给你一个或多个shell 变量。
read 从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量,如果变量名没有指定,默认标准输入的值赋值给系统内置变量REPLY
格式
read [options]...[name...]#常见参数说明-p 指定要输入内容的提示-s 静默输入,常用于密码-n N N 为数字,用于指定输入的字符长度N-d \'字符\' 输入结束符-t N N为数字,用于设置多少秒没有输入动作,则结束输入
范例
[root@CentOS8 scripts]#readdawn[root@CentOS8 scripts]#echo $REPLYdawn[root@CentOS8 scripts]#read -p \"Please input your name: \" NAMEPlease input your name: dawn[root@CentOS8 scripts]#echo $NAMEdawn# 面试题:read 和输入重定向[root@CentOS8 scripts]#read i j < test.txt ; echo i=$i j=$ji=1 j=2[root@CentOS8 scripts]#echo 1 2 |read x y;echo x=$x y=$yx= y=[root@CentOS8 scripts]#echo 1 2 |( read x y;echo x=$x y=$y; )x=1 y=2[root@CentOS8 scripts]#echo 1 2 |{ read x y;echo x=$x y=$y; }x=1 y=2