全套学习资料移步至公众号【学神来啦】更多学习资料添加扣扣资源群: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
更多学习资料请移步至公众号【学神来啦】