视频参考:https://www.bilibili.com/video/BV1mW411i7Qf?from=search&seid=11812550775556654179
一、条件判断
1、按照文件类型进行判断
测试选项 | 作 用 |
---|---|
-b 文件 | 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真) |
-c文件 | 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真) |
-d 文件 | 判断该文件是否存在,并且是否为目录文件(是目录为真) |
-e 文件 | 判断该文件是否存在(存在为真) |
-f 文件 | 判断该文件是否存在,并且是否为普通文件(是普通文件为真) |
-L 文件 | 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真) |
-p 文件 | 判断该文件是否存在,并且是否为管道文件(是管道文件为真) |
-s 文件 | 判断该文件是否存在,并且是否为非空(非空为真) |
-S 文件 | 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真) |
- 两种判断格式
ly2@DGX:~$ test -e student.txt # 第一种,常用于人为判断
ly2@DGX:~$ echo $? # 判断上一条语句是否正确运行,是0否非0
0
ly2@DGX:~$ [ -e student.txt ] # 第二种,注意中括号两侧有空格,程序脚本中更常用
ly2@DGX:~$ echo $?
0
ly2@DGX:~$ [ -f /ly2/student.txt ] && echo "yes" || echo "no"
no # 第一个判断命令如果正确执行,则打印yes,否则打印no
ly2@DGX:~$ [ -f ./student.txt ] && echo "yes" || echo "no"
yes
2、按照文件权限进行判断
测试选项 | 作 用 |
---|---|
-r 文件 | 判断该文件是否存在,并且是否该文件拥有读权限(有读权限为真) |
-w文件 | 判断该文件是否存在,并且是否该文件拥有写权限(有写权限为真) |
-x 文件 | 判断该文件是否存在,并且是否该文件拥有执行权限(有 执行权限为真) |
-u 文件 | 判断该文件是否存在,并且是否该文件拥有SUID权限(有SUID权限为真) |
-g 文件 | 判断该文件是否存在,并且是否该文件拥有SGID权限(有SGID权限为真) |
-k 文件 | 判断该文件是否存在,并且是否该文件拥有SBit权限(有SBit权限为真) |
ly2@DGX:~$ [ -w ./student.txt ] && echo "yes" || echo "no" # 注意中括号空格
yes # 所有者所属组,其他人,只要有一个有权限,则输出yes
3、两个文件之间进行比较
测试选项 | 作 用 |
---|---|
文件1 -nt 文件2 | 判断文件1的修改时间是否比文件2的新(如果新则为真) |
文件1 -ot 文件2 | 判断文件1的修改时间是否比文件2的旧(如果旧则为真) |
文件1 -ef 文件2 | 判断文件1是否和文件2的Inode号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法 |
ly2@DGX:~$ ln student.txt ./sh/stu.txt # 创建两个文件的硬链接
ly2@DGX:~$ ls -i student.txt # 查看student.txt的inode号
25962460 student.txt
ly2@DGX:~$ ls -i ./sh/stu.txt # 查看stu.txt的inode号
25962460 ./sh/stu.txt # inode相同则为硬链接
ly2@DGX:~$ ls -i ./sh
25962461 canshu1.sh 25962465 canshu4.sh 25962463 hello.sh
25962464 canshu2.sh 25962468 canshu5.sh 25962460 stu.txt
25962455 canshu3.sh 25962469 canshu6.sh 25962462 sum.sh
ly2@DGX:~$ [ student.txt -ef ./sh/stu.txt ] && echo "yes" || echo "no" # 判断硬链接
yes
4、两个整数之间比较
测试选项 | 作 用 |
---|---|
整数1 -eq 整数 2 | 判断整数1是否和整数2相等(相等为真) |
整数1 -ne 整数 2 | 判断整数1是否和整数2不相等(不相等位置) |
整数1 -gt 整数2 | 判断整数1是否大于整数2(大于为真) |
整数1 -lt 整数2 | 判断整数1是否小于整数2(小于位置) |
整数1 -ge 整数2 | 判断整数1是否大于等于整数2(大于等于为真) |
整数1 -le 整数2 | 判断整数1是否小于等于整数2(小于等于为真) |
ly2@DGX:~$ [ 23 -gt 22 ] && echo "yes" || echo "no"
yes
5、字符串的判断
测试选项 | 作 用 |
---|---|
-z 字符串 | 判断字符串是否为空(为空返回真) |
-n 字符串 | 判断字符串是否为非空(非空返回真) |
字串1 ==字串2 | 判断字符串1是否和字符串2相等(相等返回真) |
字串1 != 字串2 | 判断字符串1是否和字符串2不相等(不相等返回真) |
ly2@DGX:~$ name=sc # 给 name 变量赋值
ly2@DGX:~$ [ -z "$name" ] && echo "yes" || echo "no" # name为空返回真
no # name不为空
ly2@DGX:~$ aa=11
ly2@DGX:~$ bb=22
ly2@DGX:~$ [ "$aa"=="bb" ] && echo "yes" || echo "no" # 判断字符串是否相等
yes
6、多重条件判断
测试选项 | 作 用 |
---|---|
判断1 -a 判断2 | 逻辑与,判断1和判断2都成立,最终的结果才为真 |
判断1 -o 判断2 | 逻辑或,判断1和判断2有一个成立,最终的结果就为真 |
!判断 | 逻辑非,使原始的判断式取反,注意有空格 |
ly2@DGX:~$ aa=11
ly2@DGX:~$ [ -n "$aa" -a "$aa" -gt 23 ] && echo "yes" || echo "no"
no # -n判断变量aa是否为空,非空返回真,同时判断变量aa的是否大于23
# 因为变量aa的值不大于23 ,所以虽然第一个判断值为真,返回的结果也是假
ly2@DGX:~$ aa=24
ly2@DGX:~$ [ -n "$aa" -a "$aa" -gt 23 ] && echo "yes" || echo "no"
yes
二、流程控制
1、if 语句
1)单分支if条件语句
if [ 条件判断式 ]; then
程序
fi
或者
if [ 条件判断式 ]
then
程序
fi
单分支条件语句需要注意几个点
- 语句使用 结尾,和一般语言使用大括号结尾不同
- [ 条件判断式 ]就是使用 命令判断,所以中括号和条件判断式之间必须有空格
-
后面跟符合条件之后执行的程序,可以放在[ ]之后,用“;”分割。也可以换行写入,就不需要“;”了
例子:判断分区使用率
ly2@DGX:~$ df -h | grep /dev/sda2
/dev/sda2 440G 258G 159G 62% /
ly2@DGX:~$ df -h | grep /dev/sda2 | awk '{print $5}'
62%
ly2@DGX:~$ df -h | grep /dev/sda2 | awk '{print $5}' | cut -d "%" -f1
62
ly2@DGX:~/sh$ vim df1.sh
#!/bin/bash
# 统计根分区使用率
rate=$(df -h | grep "/dev/sda3" | awk '{print $5}' | cut -d "%" f1)
# 把根分区使用率作为变量值赋予变量 rate
if [ $rate -ge 80 ]
then
echo "Warning! /dev/sda3 is full!!"
fi
ly2@DGX:~/sh$ bash df1.sh
Warning! /dev/sda2 is full!
2)双分支if条件语句
if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的另一个程序
fi
- 例子1:备份mysql数据库
ly2@DGX:~/sh$ date
Mon Dec 2 10:52:53 HKT 2019
ly2@DGX:~/sh$ date +%y%m%d
191202
#!/bin/bash
# 备份 mysql 数据库
# Author: shenchao (E-mail: [email protected])
ntpdate asia.pool.ntp.org &>/dev/null # 同步系统时间
date=$(date +%y%m%d) # 把当前系统时间按照 “ 年月日 ” 格式赋予变量date
size=$(du -sh /var/lib/mysql) # 统计mysql数据库的大小,并把大小赋予size变量
if [ -d /tmp/dbbak ]
then
echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
cd /tmp/dbbak
tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null # 变量名作为文件名,避免覆盖,&...所有输出丢到回收站
rm -rf /tmp/dbbak/dbinfo.txt
else
mkdir /tmp/dbbak
echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
cd /tmp/dbbak
tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
rm -rf /tmp/dbbak/dbinfo.txt
fi
- 备份sh文件夹
ly2@DGX:~/sh$ ls # 查看sh文件夹下的文件
canshu1.sh canshu3.sh canshu5.sh hello.sh if2.sh sum.sh
canshu2.sh canshu4.sh canshu6.sh if1.sh stu.txt
ly2@DGX:~/sh$ vim if2.sh # 编写脚本程序
#!/bin/bash
# ntpdate asia.pool.ntp.org &>/dev/null
#同步系统时间
date=$(date +%y%m%d)
size=$(du -sh ../sh) # ?
if [ -d ./dbbak ]
then
echo "Date:$date!" > ./dbbak/dbinfo.txt
echo "Data size:$size" >> ./dbbak/dbinfo.txt
cd dbbak
tar -zcf sh-$date.tar.gz ../../sh dbinfo.txt
else
mkdir dbbak
echo "Date:$date!" > ./dbbak/dbinfo.txt
echo "Data size:$size" >> ./dbbak/dbinfo.txt
cd dbbak
tar -zcf sh-$date.tar.gz ../../sh dbinfo.txt
fi
ly2@DGX:~/sh$ bash if2.sh # 运行脚本
tar: Removing leading `../../' from member names
tar: Removing leading `../../' from hard link targets
ly2@DGX:~/sh$ ls # 查看sh文件夹
canshu1.sh canshu3.sh canshu5.sh dbbak if1.sh stu.txt
canshu2.sh canshu4.sh canshu6.sh hello.sh if2.sh sum.sh
ly2@DGX:~/sh$ cd dbbak
ly2@DGX:~/sh/dbbak$ ls
dbinfo.txt sh-191202.tar.gz
ly2@DGX:~/sh/dbbak$ cat dbinfo.txt # 查看dbinfo.txt时间与容量
Date:191202!
Data size:48K ../sh
ly2@DGX:~/sh/dbbak$ tar -ztvf sh-191202.tar.gz # 查看压缩包
drwxrwxr-x ly2/ly2 0 2019-12-02 11:43 sh/
-rwxr-xr-x ly2/ly2 45 2019-11-22 10:27 sh/canshu1.sh
drwxrwxr-x ly2/ly2 0 2019-12-02 11:43 sh/dbbak/
-rw-rw-r-- ly2/ly2 33 2019-12-02 11:43 sh/dbbak/dbinfo.txt
-rw-rw-r-- ly2/ly2 0 2019-12-02 11:43 sh/dbbak/sh-191202.tar.gz
-rwxr-xr-x ly2/ly2 64 2019-11-22 09:12 sh/hello.sh
-rwxr-xr-x ly2/ly2 354 2019-11-22 11:09 sh/canshu4.sh
-rwxr-xr-x ly2/ly2 487 2019-11-22 16:15 sh/canshu6.sh
-rwxr-xr-x ly2/ly2 36 2019-11-22 10:52 sh/canshu2.sh
-rwxr-xr-x ly2/ly2 352 2019-11-22 11:49 sh/canshu5.sh
-rwxr-xr-x ly2/ly2 100 2019-11-22 10:58 sh/canshu3.sh
-rw-rw-r-- ly2/ly2 228 2019-12-02 10:43 sh/if1.sh
-rw-rw-r-- ly2/ly2 97 2019-12-01 16:44 sh/stu.txt
-rw-rw-r-- ly2/ly2 514 2019-12-02 11:41 sh/if2.sh
-rwxr-xr-x ly2/ly2 115 2019-11-22 10:43 sh/sum.sh
hrw-rw-r-- ly2/ly2 0 2019-12-02 11:43 dbinfo.txt link to sh/dbbak/dbinfo.txt
- 例子2:判断apache是否启动
#!/bin/bash
# Author: shenchao (E-mail: [email protected])
port=$(nmap -sT 192.168.1.156 | grep tcp | grep http | awk '{print $2}')
# 使用 nmap 命令扫描服务器 , 并截取 apache 服务的状态 , 赋予变量 port
if [ "$port" == "open" ]
then
echo “$(date) httpd is ok!” >> /tmp/autostart-acc.log
else
/etc/rc.d/init.d/httpd start &>/dev/null
echo "$(date) restart httpd !!" >> /tmp/autostart-err.log
fi
ly2@DGX:~$ yum -y install nmap # 只有管理员可以安装
You need to be root to perform this command.
ly2@DGX:~$ nmap -sT 219.223.179.39 # 网络探测端口扫描和安全审核工具
The program 'nmap' is currently not installed. To run 'nmap' please ask your administrator to install the package 'nmap'
3)多分支if条件语句
if [ 条件判断式1 ]
then
当条件判断式1成立时,执行程序1
elif [ 条件判断式2 ]
then
当条件判断式2成立时,执行程序2
…省略更多条件
else
当所有条件都不成立时,最后执行此程序
fi
ly2@DGX:~/sh$ vim fi3.sh
#!/bin/bash
#判断用户输入的是什么文件
read -p "Please input a filename:" file
#接收键盘输入,并赋予变量file
if [ -z "$file" ]
#判断文件是否为空
then
echo "Error,please input a filename"
exit 1
elif [ ! -e "$file" ]
#判断file的值是否存在
then
echo "Your input is not a file!"
exit 2
elif [ -f "$file" ]
#判断file的值是否为普通文件
then
echo "$file is a regular file!"
elif [ -d "$file" ]
#判断file的值是否为目录文件
then
echo "$file is a directory!"
else
echo "$file is an other file!"
fi
ly2@DGX:~/sh$ bash fi3.sh # 运行脚本
Please input a filename:canshu1.sh # 输入文件名
canshu1.sh is a regular file! # canshu1是普通文件
ly2@DGX:~/sh$ bash fi3.sh # 运行脚本
Please input a filename:dbbak # 输入文件名
dbbak is a directory! # dbbak是个文件夹
ly2@DGX:~/sh$ bash fi3.sh # 运行脚本
Please input a filename:adad # 输入文件名
Your input is not a file! # adad不存在
ly2@DGX:~/sh$ echo $?
2
ly2@DGX:~/sh$ bash fi3.sh # 运行脚本
Please input a filename: # 输入文件名为空
Error,please input a filename # 提示请输入文件名
ly2@DGX:~/sh$ echo $?
1
2、case语句
多分支 ase条件语句: 语句和 语句一样都是多分支条件语句,不过和 多分支条件语句不同的是, 语句只能判断一种条件关系,而 语句可以判断多种条件关系。
case $变量名 in
“值1”)
如果变量的值等于值1,则执行程序1
;;
“值2”)
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
ly2@DGX:~/sh$ vim case.sh
#!/bin/bash
echo '如果想飞往上海,请输入“1”'
echo '如果想飞往广州,请输入“2”'
echo '如果想飞往成都,请输入“3”'
read -t 30 -p "请选择:" cho
case "$cho" in
"1")
echo "飞往上海的机票已发布"
;; # 别忘了分号;
"2")
echo "飞往广州的机票已发布"
;;
"3")
echo "飞往成都的机票已发布"
;;
*)
echo "输入错误"
;;
esac
ly2@DGX:~/sh$ bash case.sh
如果想飞往上海,请输入“1”
如果想飞往广州,请输入“2”
如果想飞往成都,请输入“3”
请选择:3
飞往成都的机票已发布
3、for循环
语法一
for 变量 in 值1 值2 值3… # 有几个值执行几次,空格间隔
do
程序
done
ly2@DGX:~/sh$ cat for1.sh
#!/bin/bash
#打印时间
for time in morning noon afternoon evening
do
echo "This time is $time!"
done
ly2@DGX:~/sh$ chmod 755 for1.sh
ly2@DGX:~/sh$ ./for1.sh
This time is morning!
This time is noon!
This time is afternoon!
This time is evening!
ly2@DGX:~/sh$ ls > sh.log
ly2@DGX:~/sh$ cat sh.log
canshu1.sh
……
canshu6.sh
case.sh
dbbak
fi3.sh
for1.sh
hello.sh
if1.sh
if2.sh
ls.lod
stu.txt
sum.sh
#!/bin/bash
#批量解压缩脚本
# Author: shenchao (E-mail: [email protected])
cd /lamp # lamp = linux + apache + Mysql + PHP
ls *.tar.gz > ls.log
for i in $(cat ls.log) # 不确定循环多少次,用变量替代
do
tar -zxf $i &>/dev/null
done
rm -rf /lamp/ls.log
ly2@DGX:~/sh$ cat for2.sh
#!/bin/bash
# 查询sh文件夹下bash脚本个数
ls *.sh > sh.log
y=1
for i in $(cat sh.log)
do
echo $y
y=$(( $y + 1 ))
done
ly2@DGX:~/sh$ bash for2.sh
1
2
3
……
ly2@DGX:~/sh$ cat sh.log
canshu1.sh
canshu2.sh
canshu3.sh
……
语法二
for (( 初始值;循环控制条件;变量变化 )) # 只有双括号括起来,才可进行加减运算
do
程序
done
ly2@DGX:~/sh$ vim for3.sh
#!/bin/bash
#从1加到100
s=0
for ((i=1;i<=100;i=i+1))
do
s=$(($s+$i))
done
echo "The sum of 1+2...+100 is:" $s
ly2@DGX:~/sh$ bash for3.sh
The sum of 1+2...+100 is: 5050
#!/bin/bash
#批量添加指定数量的用户
# Author: shenchao (E-mail: [email protected])
read -p "Please input user name: " -t 30 name
read -p "Please input the number of users: " -t 30 num
read -p "Please input the password of users: " -t 30 pass
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
# 注意 !与z有空格,判断输入三个值是否为空(-z),空(-z=1),不空(-z=0,! -z=1)
then
y=$(echo $num | sed 's/^[0-9]*$'//g')
# 判断num是否为数字,是的话,返回空值赋给y
if [ -z "$y" ] # 如果 y 的值为空,继续运行
then
for (( i=1;i<=$num;i=i+1 ))
do
/usr/sbin/useradd $name$i &>/dev/null
echo $pass | /usr/bin/passwd --stdin "$name$i" &>/dev/null
done
fi
fi
4、while循环与until循环
1)while循环
循环是不定循环,也称作条件循环。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。这就和 的固定循环不太一样了。
while [ 条件判断式 ]
do
程序
done
ly2@DGX:~/sh$ cat while.sh
#!/bin/bash
#从1加到100
i=1
s=0
while [ $i -le 100 ]
#如果变量i的值小于等于100,则执行循环
do
s=$(($s+$i))
i=$(($i+1))
done
echo "The sum is: $s"
ly2@DGX:~/sh$ bash for4.sh
The sum is: 5050
2)until循环
循环,和 循环相反, 循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。
until [ 条件判断式 ]
do
程序
done
ly2@DGX:~/sh$ cat until.sh
#!/bin/bash
#从1加到100
i=1
s=0
until [ $i -gt 100 ]
#循环直到变量i的值大于100,就停止循环
do
s=$(($s+$i))
i=$(($i+1))
done
echo "The sum is: $s"
ly2@DGX:~/sh$ bash until.sh
The sum is: 5050