shell 脚本 - 格式化输出、运算符以及read输入

格式化输出 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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值