格式化输出 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 3
1.00
2.00
3.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 4
1 2
3 4
[root@CentOS8 ~]#printf "%s %s %s\n" 1 2 3 4
1 2 3
4
#制表,表格形式输出
[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" $VAR
what
is
it?
#加引号,将变量中的内容视为整体
[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 $i
30
[root@CentOS8 ~]#j=20
[root@CentOS8 ~]#let i*=j
[root@CentOS8 ~]#echo $i
600
[root@CentOS8 ~]#unset i j;
[root@CentOS8 ~]#i=10
[root@CentOS8 ~]#j=20
[root@CentOS8 ~]#declare -i result=i*j
[root@CentOS8 ~]#echo $result
200
[root@CentOS8 ~]#echo "scale=3;20/3" | bc
6.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.sh
1 #!/bin/bash
2 #********************************************************************
3 # Author:dawn
4 # Date:2020-08-08 15:38:19
5 # FileName:chook_rabbit.sh
6 # URL:https://blog.csdn.net/xiao_dan_
7 # Version:1.0
8 # Description:The test script
9 #********************************************************************
10 HEAD=$1
11 FOOT=$2
12
13 RABBIT=$(((FOOT-HEAD-HEAD)/2))
14 CHOOK=$[HEAD-RABBIT]
15 echo RABBIT:$RABBIT
16 echo CHOOK:$CHOOK
[root@CentOS8 script]#bash chook_rabbit.sh 30 80
RABBIT:10
CHOOK:20
逻辑运算符
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异或得到结果Z,Z再和任意两者之一X异或,将得出另一个值Y
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
范例
#异或用于两个值之间的交换
[root@CentOS8 script]#x=10;y=20;temp=$x;x=$y;y=$temp;echo x=$x,y=$y
x=20,y=10
[root@CentOS8 script]#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 必须参与运算,才能得到最终的结果
关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字
-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 $FILE
args.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,否则,不执行cmd2
cmd1 || 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 haha
haha: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 exist
haha 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]#read
dawn
[root@CentOS8 scripts]#echo $REPLY
dawn
[root@CentOS8 scripts]#read -p "Please input your name: " NAME
Please input your name: dawn
[root@CentOS8 scripts]#echo $NAME
dawn
# 面试题:read 和输入重定向
[root@CentOS8 scripts]#read i j < test.txt ; echo i=$i j=$j
i=1 j=2
[root@CentOS8 scripts]#echo 1 2 |read x y;echo x=$x y=$y
x= 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