您的位置:首页 > 运维架构 > Shell

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

2020-08-11 10:56 1461 查看

格式化输出、运算符以及read输入

  • 短路运算
  • 关系运算符
  • 条件测试命令
  • 接受输入 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
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: