全套学习资料移步至公众号【学神来啦】更多学习资料添加扣扣资源群:661308959

本节所讲内容:

  20.1  read命令键盘读取变量的值

  20.2  流程控制语句if

  20.3  test测试命令

  20.4  流程控制过程中复杂条件和通配符

  20.5  实战-2个shell脚本实战

20.1  read命令键盘读取变量的值

从键盘读取变量的值,通常用在shell脚本中与用户进行交互的场合。该命令可以一次读取多个变量的值,变量和输入的值都需要使用空格隔开。在read命令后面,如果没有指定变量名,读取的数据将被自动赋值给特定的变量REPLY

read从键盘读入数据,赋给变量

例1:

[root@xuegod63 ~]# read a b

hello world

[root@xuegod63 ~]# echo $a $b

hello world

read常用见用法及参数

read 选项

-p “提示信息”:等待read输入时,输出提示信息。

-t 秒数:read命令会一直等待用户输入,使用此选项可以指定等待时间。

-n 字符数:read命令只接受指定的字符数量,然后就会执行。

-s 隐藏输入内容,适用于机密信息的输入。

例1:从标准输入读取一行并赋值给变量

[root@xuegod63 ~]# read passwd

例2:读取多个值,从标准输入读取一行,直至遇到第一个空白符或换行符。把用户键入的第一个词存到变量first中,把该行的剩余部分保存到变量last中

[root@xuegod63 ~]# read first last

aaaa  bbbb

例3:read -s passwd 将你输入的东西隐藏起来,值赋给passwd。这个用户隐藏密码信息

[root@xuegod63 ~]# read -s passwd

[root@xuegod63 ~]# echo $passwd

123456

例4:输入的时间限制

[root@xuegod63 ~]# read -t 2 username #超过两秒没有输入,直接退出,输入了,不敲回车,也不会保存变量值

例5:输入的长度限制(不常用)

[root@xuegod63 ~]# read -n 2 test  #最多只接受2个字符

例6:使用-r参数输入,允许让输入中的内容包括: 斜线识别为普通字符。

[root@xuegod63 ~]# read line

\n

[root@xuegod63 ~]# echo $line

n

[root@xuegod63 ~]# read  -r line

\n

[root@xuegod63 ~]# echo $line

\n

例7:-p 用于给出提示符,在前面的例子中我们使用了echo –n “…“来给出提示符

方法1:

[root@xuegod63 ~]# read -p  "please input: "  pass

please input: 123456

[root@xuegod63 ~]# echo $pass

123456

方法2:

[root@xuegod63 ~]# echo -n "please input: " ; read pass

please input: 123456     

[root@xuegod63 ~]# echo $pass

123456

echo -n 不输出行尾的换行符

例8:read 综合实例

[root@xuegod63 ~]# vim  test-read.sh  #写入以下内容

#!/bin/bash

read -p "请输入姓名:" NAME

read -p "请输入年龄:" AGE

read -p "请输入性别:" SEX

cat<<eof

*********************

你的基本信息如下:

姓名: $NAME

年龄:$AGE

性别:$SEX

********************

eof

[root@xuegod63 ~]# sh test-read.sh

请输入姓名:xuegod

请输入年龄:111

请输入性别:man

*********************

你的基本信息如下:

姓名: xuegod

年龄:111

性别:man

20.2  流程控制语句if

20.2.1  语法格式

if  条件   

then

   commands

fi

if语句流程图:

注:根据我们的命令退出码来进行判断(echo $? =0),如果是0,那么就会执行then后面的命令

例1:

set paste

[root@xuegod63 ~]# vim  if0.sh

#!/bin/bash

if ls /tmp

then

        echo "it's ok"

fi

20.2.2  双分支if语句

语法格式:

if command  ; then

commands

else

commands

fi

[root@bogon ~]# vim if1.sh

#!/bin/bash

read -p "检查目录是否存在,请输入目录:" dir

if ls $dir  2> /dev/null 1>&2

then

echo "目录存在"

else

echo "目录不存在"

fi

例2:

[root@xuegod63 ~]# vim if2.sh

#!/bin/bash

if grep "root:x" /etc/passwd;then

        echo "it's ok"

else

        echo "it's err"

fi

[root@xuegod63 ~]# sh if2.sh

root:x:0:0:root:/root:/bin/bash

it's ok

例3:

[root@xuegod63 ~]# vim if3.sh

#!/bin/bash

if grep "xuegod" /etc/passwd;then

        echo "it's ok"

else

        echo "it's err"

fi

[root@xuegod63 ~]# sh if3.sh

it's err

20.2.3  多分支if语句

语法结构:

if条件测试操作1 ; then

commands

elif  条件测试操作2  ; then

commands

elif 条件测试操作3 ; then

commands

.......

else

commands

fi

例4:判断用户在系统中是否存在,是否有家目录

[root@xuegod63 ~]# vim if4.sh

#!/bin/bash

read -p "input a user:" user

if grep $user /etc/passwd ; then

        echo "用户 $user 已存在"

elif ls -d /home/$user  > /dev/null 2>&1 ;  then

        echo "$user 不存在,但家目录存在"

else

        echo "用户 $user 不存在"

        echo "$user 家目录不存在"

fi

[root@xuegod63 ~]# useradd user1

[root@xuegod63 ~]# sh if4.sh

input a user:user1

user1:x:1000:1000::/home/user1:/bin/bash

用户 user1 已存在

[root@xuegod63 ~]# userdel user1

[root@xuegod63 ~]# sh if4.sh

input a user:user1

/home/user1

input a user:user1

user1 不存在,但家目录存在

[root@xuegod63 ~]# sh if4.sh

input a user:xuegod

用户 xuegod 不存在

xuegod 家目录不存在

#if另一种书写格式,不使用;分号,需要换行

[root@xuegod63 ~]# vim if5.sh

#!/bin/bash

read -p "input a user:" user

if grep $user /etc/passwd

then

        echo "用户 $user 已存在"

elif ls -d /home/$user  > /dev/null 2>&1

then

        echo "$user 不存在,但家目录存在"

else

        echo "用户 $user 不存在"

        echo "$user 家目录不存在"

fi

20.3  test测试命令

Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试

格式:test 测试条件

如果结果是对的,也叫结果为真,用$?=0表示,反之为假,用非0表示

equal 等于;not equal to 不等于;greater than 大于; less than 小于;

20.3.1  数值比较

参数 说明 示例

-eq 等于则为真 [ “$a” -eq “$b” ]

-ne 不等于则为真 [ “$a” -ne “$b” ]

-gt 大于则为真 [ “$a” -gt “$b” ]

-ge 大于等于则为真 [ “$a” -ge “$b” ]

-lt 小于则为真 [ “$a” -lt “$b” ]

-le 小于等于则为真 [ “$a” -le “$b” ]

例1:比较大小

[root@xuegod63 ~]# vim test1.sh

#!/bin/bash

if test 2 -eq 1; then

        echo ok

else

        echo err

fi

if [ 2 -eq 2 ];then

        echo ok

else

        echo err

fi

[root@xuegod63 ~]# sh test1.sh

[root@xuegod63 ~]# if test 2 -ne 1;then echo "true";else echo "false";fi

true

[root@xuegod63 ~]# if test 1 -ne 1;then echo "true";else echo "false";fi

false

[root@ xuegod63 ~]# [ 3 -ge 2 ] && echo "true" || echo "false"      #注意括号中的空格

true

[root@ xuegod63 ~]# [ 2 -ge 2 ] && echo "true" || echo "false"

true

[root@ xuegod63 ~]# [ 1 -ge 2 ] && echo "true" || echo "false"

false

[root@ xuegod63 ~]# vim test2.sh

#!/bin/bash

read -p "请输入第一个整数" a

read -p "请输入第二个整数" b

if [ $a -lt $b ];then

        echo "$a小于$b "

else

        echo "$a不小于$b"

fi

[root@xuegod63 ~]# sh test2.sh

20.3.2  字符串比较

参数. 说明 示例

== 或 = 等于则为真 [ “$a” == “$b” ]

!= 不相等则为真 [ “$a” != “$b” ]

-z 字符串. 字符串的长度为零则为真 [ -z “$a” ]

-n 字符串 字符串的长度不为空则为真 [ -n “$a” ]

str1 > str2 str1大于str2为真 [ str1 \> str2 ]

str1 < str2 str1小于str2为真 [ str1 \< str2 ]

例1:根据用户名判断是否是超级管理员

[root@ xuegod63 ~]# vim test3.sh

#!/bin/bash

read -p "请输入你的名字" name

if [ $name == "root" ];then

        echo "管理员"

else

        echo "不是管理员"

fi

[root@xuegod63 ~]# [ -z "111111111" ]      #长度不为零为假

[root@xuegod63 ~]# echo $?

1

[root@xuegod63 ~]# [ -z "" ]                 #长度为零为真

[root@xuegod63 ~]# echo $?

0

[root@xuegod63 ~]# test -n "111111111"   #长度不为空为真

[root@xuegod63 ~]# echo $?

0

[root@xuegod63 ~]# test -n ""              #长度为空为假

[root@xuegod63 ~]# echo $?

1

例2:在做字符串大小比较的时候,注意字符串的顺序

大于号和小于号必须转义,要不然SHELL会把它当成重定向符号

大于和小于它们的顺序和sort排序是不一样的

在test比较测试中,它使用的是ASCII顺序,大写字母是小于小写字母的;sort刚好相反

扩展: ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。

[root@ xuegod63 ~]# vim test4.sh

#!/bin/bash

read -p "输入第一个字符" var1

read -p "输入第二个字符" var2

if [ $var1 \> $var2 ];then

        echo "$var1 > $var2"

else

        echo "$var1 < $var2"

fi

if test $var1 \> $var2;then

        echo "$var1 > $var2"

else

        echo "$var1 < $var2"

fi

[root@xuegod63 ~]# sh test4.sh

输入第一个字符a

输入第二个字符A

a > A

a > A

20.3.3  文件比较

参数 说明 示例

-e 文件名 如果文件或目录存在则为真 [ -e file ]

-r 文件名 如果文件存在且可读则为真 [ -r file ]

-w 文件名 如果文件存在且可写则为真 [ -w file ]

-x 文件名 如果文件存在且可执行则为真 [ -x file ]

-s 文件名 如果文件存在且至少有一个字符则为真 [ -s file ]

-d 文件名 如果文件存在且为目录则为真 [ -d file ]

-f 文件名 如果文件存在且为普通文件则为真 [ -f file ]

-c 文件名 如果文件存在且为字符型文件则为真 [ -c file ]

-b 文件名 如果文件存在且为块特殊文件则为真 [ -b file ]

file1 -nt fle2 检查file1是否比file2新 [ file1 -nt file2 ]

file1 -ot file2 检查file1是否比file2旧 [ file1 -ot file2 ]

[root@ xuegod63 ~]# [ -e /etc/passwd ] && echo "true" || echo "false"

tree

[root@ xuegod63 ~]# [ -e /etc/pass ] && echo "true" || echo "false"

false

可以创建一个空文件,和-s对比一下

[root@xuegod63 ~]# touch aaa

[root@xuegod63 ~]# [ -s aaa ];echo $?

1

[root@xuegod63 ~]# echo abcd > aaa

[root@xuegod63 ~]# test -s aaa;echo $?

0

例1:

[root@xuegod63 ~]# vim  /tmp/test5.sh

#!/bin/bash

if [ -w /etc/passwd ];then

        echo ok

else

        echo err

fi 

[root@xuegod63 ~]# sh /tmp/test5.sh

ok

[root@xuegod62 ~]# useradd user1

[root@xuegod62 ~]# su - user1

[user1@xuegod62 ~]$ sh /tmp/test5.sh

err

[user1@xuegod62 ~]$ exit

[root@xuegod62 ~]# chmod a+w /etc/passwd

[root@xuegod62 ~]# su - user1

[user1@xuegod62 ~]$ sh /tmp/test5.sh

ok

例2:

[root@xuegod63 ~]# test -e /etc/aaa.txt && echo ok || echo err

err

[root@xuegod63 ~]# test -e /etc/passwd && echo ok || echo err

ok

[root@xuegod63 ~]# test -e /etc && echo ok || echo err

ok

[root@xuegod63 ~]# touch a.txt          #先创建a.txt

[root@xuegod63 ~]# touch b.txt          #后创建b.txt

[root@xuegod63 ~]# [ a.txt -nt b.txt  ]      #检查a.txt比b.txt

[root@xuegod63 ~]# echo $?

1

[root@xuegod63 ~]# [ a.txt -ot b.txt  ]      #检查a.txt比b.txt

[root@xuegod63 ~]# echo $?

0

例:清空日志目录

 [root@ xuegod63 ~]# vim /tmp/log.sh

#!/bin/bash

# 这是清空日志脚本

# 判断当前用户是否为root

if [ $USER != "root" ];then

        echo "脚本需要root用户执行"

        exit 10  #直接退出,并返回10

fi

# 判断文件是否存在,!取反

#文件存在的情形下-f /var/log/messages,为真,取反,表达式结果为假。不会执行then后面的内容,echo "文件不存在"

#文件不存在的情形下,-f /var/log/messages,为假,取反,表达式结果为真。会执行then后面的内容,echo "文件不存在"

if [ ! -f /var/log/messages ];then

        echo "文件不存在"

        exit 12

fi

# 保留最近100行的日志内容。

tail -100 /var/log/messages > /var/log/mesg.tmp

# 日志清空

> /var/log/messages

 mv /var/log/mesg.tmp /var/log/messages

 echo "log clean up"              

exit #退出bash,并返回一个值      注:退出码 exit ,取值范围是0-255,超过后值循环0-255

[root@xuegod63 ~]# sh /tmp/log.sh

log clean up

测试普通用户执行此脚本:

[root@xuegod63 ~]# useradd user666

[root@ xuegod63 ~]# su - user666

[user666@xuegod63 ~]$ echo $USER

user666

[user666@xuegod63 ~]$ sh /tmp/log.sh

脚本需要root用户执行

[user666@xuegod63 ~]$ echo $?

10

例:exit 退出bash,并返回一个值

[root@xuegod63 ~]# su - user666

[user666@xuegod63 ~]$ exit 10

[root@xuegod63 ~]# echo $?

10

20.4  流程控制过程中复杂条件和通配符

20.4.1  多个判断条件

判断第一种:两个条件都为真或有一个为真就执行

if [ 条件判断一 ] && [ 条件判断二 ]; then    

   命令一

elif [ 条件判断三 ] || [ 条件判断四 ]; then

    命令二

else

    执行其它

fi

#!/bin/bash

if [ -d /etc ] && [ -d /root ];then

        echo "etc和root目录都存在"

fi

if [ -d /etc ] || [ -d /root ];then

        echo "etc或root目录至少有一个存在"

fi

判断第二种

if [条件判断一 -a  条件判断二 -a  条件判断三]; then

elif [条件判断三  -o 条件判断四 ]; then

else

   执行其它

fi

#!/bin/bash

if [ -d /etc  -a  -d /root ];then

        echo "etc和root目录都存在"

fi

if [ -d /etc  -o  -d /root ];then

        echo "etc或root目录至少有一个存在"

fi

判断第三种

if [[ 条件判断一 && 条件判断二 ]]; then

elif [[ 条件判断三  || 条件判断四 ]]; then

else

   执行其它

fi

#!/bin/bash

if [[ -d /etc  &&  -d /root ]];then

        echo "etc和root目录都存在"

fi

if [[ -d /etc  ||  -d /root ]];then

        echo "etc或root目录至少有一个存在"

fi

例1:设置umask 权限掩码

参考: [root@xuegod63 ~]# vim /etc/profile  

[root@xuegod63 ~]# vim  umask.sh

#-gn表示用名称显示group。-un表示用名称方式显示用户名,判断组和用户是否相同。

if [ $UID -gt 199 ] && [ "`id -gn`" = "`id -un`" ]; then

        echo "umask 002"

else    

        echo "umask 022"

fi

[root@xuegod63 ~]# sh  umask.sh

umask 022

() 单小括号 (())双小括号

[] 单中括号  [[]]  双中括号

{} 大括号

例2:[[ 。。。 ]]和[ 。。。]的区别

[[ ]] 运算符是[ ]运算符的扩充;[[ ]]能够支持 *,< 、>等符号且不需要转义符

例1:

[root@xuegod63 ~]# if [[ $USER == r* ]] ; then echo true ; else echo false ; fi

注: [[ $USER == r* ]]对比时,  r* 表示以r开头的任意长度字符串,这样就包括root

当只有一个[] 中括号时:

[root@xuegod63 ~]# if [ $USER == r* ] ; then echo true ; else echo false ; fi

注: [ $USER == r* ]对比时,  r* 就表示 r*

也可以这样写:

[root@xuegod63 ~]# if [[ $USER == [a-z]oot ]] ; then echo true ; else echo false ; fi

[[ 。。。 ]]和[ 。。。],() 和(())的区别汇总:

()单小括号:

多条命令执行:

括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。

单小括号,(cmd1;cmd2;cmd3) 新开一个子shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后可以没有分号。

[root@xuegod63 ~]# (cc=1;dd=2,ee=3)

[root@xuegod63 ~]# echo $cc $dd $ee

多条命令执行:

{} 花括号,大括号,{ cmd1;cmd2;cmd3;} 在当前shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后必须有分号, 第一条命令和左括号之间必须用空格隔开。

[root@xuegod63 ~]# { c=1;d=2;e=3;}

[root@xuegod63 ~]# echo $c $d $e

1、所有的字符与逻辑运算符直接用“空格”分开,不能连到一起。

2、在[ ]表达式中,常见的> 、<需要加转义符\,大小比较

3、进行逻辑运算符&& 、||比较时;如果用的[ ]符号,则用在外面,如[ ] && [ ] || [ ]如果在[]里面进行逻辑与或的比较,则用-a、-o进行表示,如[ x = y a x < z o x > m ]

4、[[ ]] 运算符只是[ ]运算符的扩充;能够支持< 、>符号运算不需要转义符;它还是以字符串比较大小。里面支持逻辑运算符 || 、 && , 不再使用-a 、-o

5、[[]] && 而不是 -a 表示逻辑“与”;用 || 而不是 -o表示逻辑“或”

6、[[ ]]可以进行算术扩展,而[ ... ]不可以

7、[[...]]能用正则,而[...]不行

8、双括号((  ))用于数学表达式

9、双方括号号[[  ]]用于高级字符串处理,比如“模糊匹配”

10、[[]]对于字符串的比较支持并不好,尤其在使用[[]]和<>符号进行比较的时候会出现返回值错误的情况。

20.4.2  shell中的通配符

shell常见通配符:

字符 含义

* 匹配 0 或多个字符

? 匹配任意一个字符

[abcd] 匹配 abcd中的任意单一字符

[!abcd] 匹配 除abcd中的任意单一字符

[0-9] 匹配 0-9 中的任意单一字符 如:[a-z]

{string1,string2,...} 匹配 sring1 或 string2 (或更多)其中一个字符串

例:

[root@xuegod63 ~]#  ls /etc/*.conf

[root@xuegod63 ~]# ls /etc/???.conf

/etc/nfs.conf  /etc/sos.conf  /etc/yum.conf

[root@xuegod63 ~]# touch  /opt/a{1,2,3}.txt

[root@xuegod63 ~]# ls /opt/a[13].txt

/opt/a1.txt  /opt/a3.txt

[root@xuegod64 ~]# ls /opt/a[!12].txt

/opt/a3.txt

[root@xuegod64 ~]# ls /opt/a[1-3].txt

/opt/a1.txt  /opt/a2.txt  /opt/a3.txt

大括号拓展。(通配)将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt

[root@xuegod63 ~]# rm -f *.txt

[root@xuegod63 ~]# touch {a{1..3},b,c,d}.txt

[root@xuegod63 ~]# ls *.txt

20.5  实战-3个shell脚本实战

20.5.1  实战1:编写脚本检查服务器运行状态

[root@xuegod64 ~]# vim status.sh

#!/bin/bash

if [ $# -ge 1 ] ;then

        systemctl status $1 > /dev/null

        if [ $? -eq 0 ] ;then

                echo "$1 服务正常运行"

        else

                systemctl start $1

                echo "$1 服务没有运行,已经尝试启动该服务"

        fi

else

                echo "执行脚本的格式"

                echo "sh $0 服务名"

fi

[root@xuegod64 ~]# systemctl stop rsyslog

[root@xuegod64 ~]# sh status.sh rsyslog

rsyslog 服务没有运行,已经尝试启动该服务

[root@xuegod64 ~]# sh status.sh rsyslog

rsyslog 服务正常运行

20.5.2  实战2:根据学生的成绩判断学生的优劣

[root@xuegod63 ~]# vim  check_cj.sh  

#!/bin/bash

read  -p   "请输入你的成绩  "   cj

if   [ $cj   -ge  0  ]    &&  [  $cj  -le  59  ]  ;then

     echo   "补考"

elif  [  $cj  -ge  60 ]    &&  [  $cj  -le  70   ]   ;then

    echo  "良好"

elif     [ $cj -ge 71 ]     &&  [ $cj   -le  85 ]   ;then

   echo  "好"

elif [ $cj  -ge 86 ]     &&  [   $cj  -le  100 ]   ;then

    echo  "优秀"

else

   echo "成绩的有效范围是0-100之间"

fi

20.5.3  实战3:自动备份数据库

每周一晚上3:00 ,备份数据库服务器上webdb库的所有数据到系统的/mysqlbak目录里,使用系统日期做备份文件名。

[root@xuegod63 ~]# vim   mysqlbak.sh

#!/bin/bash

baknamefile=`date +%Y-%m-%d`

bakdir=/mysqlbak

user=root

password=123

dbname=webdb

[  -d  $bakdir   ]   ||    mkdir    $bakdir

mysqldump   -u$user   -p$password  --flush-logs  $dbname   >    $bakdir/${baknamefile}-webdb.sql

因为mysql咱们还没有学,这里以/etc目录来做实验:

[root@xuegod63 ~]# vim etcbak.sh

#!/bin/bash

baknamefile=`date +%Y-%m-%d`

bakdir=/etcbak

srcdir=/etc

[ -d $bakdir  ] || mkdir $bakdir

tar czvf ${bakdir}/${baknamefile}-etc.tar.gz ${srcdir}

echo "===================================="

ls -lh ${bakdir}/${baknamefile}-etc.tar.gz

echo "back etc is ok!"

[root@xuegod63 ~]# chmod +x  etcbak.sh

[root@xuegod63 ~]# ./etcbak.sh

[root@xuegod63 ~]# crontab  -e

0 3 * * * /root/etcbak.sh   >/dev/null   2>&1

更多学习资料请移步至公众号【学神来啦】