Shell环境根据命令执行后的返回状态值($?)来判断是否执行成功,当返回值为0时表示成功,否则(非0值)表示失败或异常。
测试工具——test命令
test
操作符 作用
-d 测试文件是否为目录文件(Directory)
-f 测试文件是否为普通文件(File)
-e 测试目录或文件是否存在(Exist)。建议使用-e,-a可能不准确。
-a 测试目录或文件是否存在(Exist)
-r 测试当前用户是否有权限读取(Read)
-w 测试当前用户是否有权限写入(Write)
-x 测试当前用户是否有权限执行(eXcute)
-L 测试是否为符号链接(软链接文件)
-nt 判断文件A是否比文件B新-ot判断文件A是否比文件B旧
-ef 判断两个文件是否为同一文件。可用于硬链接,主要判断两个文件是否指向同一个inode。
-s FILE 判断文件是否存在且非空
-t fd fd 指定文件描述符是否在某终端已经打开
-N FILE 文件自从上一次被读取之后是否被修改过
-O FILE 当前有效用户是否为文件属主
-G FILE 当前有效用户是否为文件属组
操作符 含义
-eq 等于(Equal)
-ne 不等于(Not Equal)
-gt 大于(Greater Than)
-lt 小于(Lesser Than)
-le 小于或等于(Lesser or Equal)
-ge 大于或等于(Greater or Equal)
逻辑测试(短路运算)
-a或&& :逻辑与,“而且”的意思,全真才为真。
-o或|| :逻辑或,“或者”的意思,一真即为真。
! :逻辑否。
使用三元运算符
使用 if语句双分支结构
ping命令:
-c,发送包的个数。
-i,发送的间隔时间。
-w(小写),多少秒后停止ping操作。
-W(大写),以毫秒为单位设置ping的超时时间 。
1.
if 判断条件
then 条件成立的分支代码
fi
2.
if 判断条件1
then
条件1为真的分支代码
elif 判断条件2
then
条件2为真的分支代码
elif 判断条件3
then
条件3为真的分支代码
...
else
以上条件都为假的分支代码
fi
3.
case 变量引用 in
模式1)
命令分支1
;;
模式2)
命令分支2
;;
...
*)
默认命令分支
esac
测试文件是否存在时,建议使用-e。如:[ -e /etc/passwd ]
七个小实验
检查用户家目录中的 test.sh 文件是否存在,并且检查是否有执行权限。
vim cunzai.sh
#!/bin/bash
#author:yu
#date:2022/04/08
[ -e ~/test.sh ]
if [ $? -eq 0 ];then
echo "test.sh存在"
[ -x ~/test.sh ]
if [ $? -eq 0 ];then
echo "有执行权限"
else
echo "没有执行权限"
fi
else
echo "test.sh不存在"
fi
提示用户输入100米赛跑的秒数,要求判断秒数大于0且小于等于10秒的进入决赛,大于10秒的都淘汰,如果输入其它字符则提示重新输入;进入决赛的成员再进一步判断男女性别,男生进男生组,女生进女生组,如果输入错误请提示错误。
vim paobu.sh
read -p "请输入您的100米赛跑秒数:" time
if [ $time -gt 0 ] && [ $time -le 10 ]
then
echo "恭喜您进入决赛"
read -p "请输入您的性别(男、女):" gender
if [ $gender = "男" ]
then
echo "您进入男生组"
elif [ $gender = "女" ]
then
echo "您进入女生组"
else
echo "输入有误,请重新输入"
fi
elif [ $time -gt 10 ]
then
echo "很遗憾,您无缘决赛"
else
echo "输入有误,请重新输入"
bash $0
fi
用case语句解压根据后缀名为 .tar.gz 或 .tar.bz2 的压缩包到 /opt 目录。
case $1 in
*.tar.gz)
echo "解压gz格式的压缩包"
tar -zxvf $1 -C /opt/
;;
*.tar.bz2)
echo "解压bz2格式的压缩包"
tar -jxvf $1 -C /opt/
;;
*)
echo "文件格式有误,无法解压"
esac
提示用户输入内容,使用if 语句判断输入的内容是否为整数
vim zhengshu.sh
#!/bin/bash
#判断用户输入的数是否为整数
read -p "请输入一个数字:" a
let i=$a+1 &> /dev/null
if [ $? -eq 0 ]
then
echo "${a}是整数"
else
echo "${a}不是整数"
fi
根据上一题,在整数的情况下再判断输入的内容是奇数还是偶数。
vim jishu.sh
#!/bin/bash
#判断用户输入的数是否为整数
#如果是整数,则继续判断是奇数还是偶数。
read -p "请输入一个数字:" a
let i=$a+1 &> /dev/null
if [ $? -eq 0 ]
then
echo "$a是整数"
b=$[${a}%2]
case $b in
0)
echo "$a是偶数"
;;
*)
echo "$a是奇数"
esac
else
echo "$a不是整数"
fi
用case语句在/etc/init.d/目录中写一个firewalld脚本,并加入到系统服务管理中(#chkconfig: 2345 99 20),使能够使用 service firewalld start|stop|restart|status 来管理firewalld服务;如果命令选项不对,则提示 “用法: $0 {start|stop|status|restart}”
cd /etc/init.d
vim firewalld
#!/bin/bash
#chkconfig: 2345 99 20 //必须加这一行,该脚本才能被chkconfig管理
case $1 in
start)
echo "正在启动firewalld"
systemctl start firewalld
;;
stop)
echo "正在关闭firewalld"
systemctl stop firewalld
;;
status)
echo "查看firewalld的状态"
systemctl status firewalld
;;
restart)
echo "正在重启firewalld"
systemctl restart firewalld
;;
*)
echo "用法: $0 {start|stop|status|restart}"
esac
chmod +x firewalld //为脚本增加执行权限
chkconfig --add firewalld //把该脚本加入系统服务管理中
chkconfig --list firewalld
service firewalld start
service firewalld stop
service firewalld status
循环:遍历、迭代、递归 。
遍历(traversal) - 按规则访问非线性结构中的每一项。
迭代(iterate) - 按顺序访问线性结构中的每一项。
递归(recursion) - 在函数内调用自身, 将复杂情况逐步转化成基本情况
常见的循环命令:for, while, until。
for循环语句 遍历
1.依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束。
2.如果省略 [in WORDS ... ] ,此时使用位置参数变量 in "$@"
for 变量名 in 取值列表
do
命令序列
done
for遍历三种方式:
for i in {1..10}
for i in $(seq 1 10)
for ((i=1;i<=10;i++))
遍历奇数的三种方式
for i in {1..10..2}
for i in $(seq 1 2 10)
for ((i=1;i<=10;i+=2))
遍历偶数:
for i in {2..10..2}
for i in $(seq 2 2 10)
for ((i=2;i<=10;i+=2))
示例1 批量添加用户
用户名存放在users.txt文件中,每行一个
初始密码均设为123456
vim users.txt
liyi
lisan
liwu
liliu
vim for2.sh
for user in $(cat /root/users.txt)
do
useradd $user
echo "123456" | passwd --stdin $user
done
bash for2.sh
实列2:根据IP地址检查主机状态
IP地址存放在ips.txt文件中,每行一个
使用ping命令检测各主机的连通性
vim ips.txt
192.168.92.10
192.168.92.22
192.168.92.1
vim for3.sh
for host in $(cat /data/ips.txt)
do
ping -c 3 -i 0.5 -w 4 $host &> /dev/null
if [ $? -eq 0 ]
then
echo "$host is up"
else
echo "$host is down"
fi
done
实列三:生成8位随机密码(使用字符串分片的方法)
生成8位随机密码,密码范围为26个大小写英文字母和10个阿拉伯数字。
先定义密码取值范围:26个大小写英文字母和10个阿拉伯数字
每次取1个字符。
循环取8次
vim passran.sh
string="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
for i in {1..8}
do
#每次循环随机获取0到字符串长度减1的下标值
num=$[RANDOM % ${#string}]
#进行字符串截取,每次随机取出1个字符
var=${string:$num:1}
#每次追加生成的密码,passwd+=$var等同于passwd=$passwd$var
passwd+=$var
done
echo "本次生成的密码为:$passwd"
多线程执行脚本(并行执行)
普通for循环是串行,一个一个执行。
在do和done中间增加 { } 符号,可以多线程同时执行。
ping 192.168.72.0/24网段内的所有主机。
vim for4.sh
#!/bin/bash
#多线程,同时ping多台主机
for ip in 192.168.72.{1..254}
do
{
ping -c3 -w2 $ip &>/dev/null
if [ $? -eq 0 ]
then
echo "$ip is up" >> /opt/up.txt
else
echo "$ip is down" >> /opt/down.txt
fi
}&
#{ }表示多线程同时执行
#增加 & 符号,表示将进程放到后台运行,后台命令之间是不区分先来后到关系的
done
wait
分隔符的作用演示:
使用for读取文件内容,文件中有空格
for的三个默认分隔符
空格、制表符 \t、换行符 \n。
使用for读取文件内容,文件中有空格
vim fen1.sh //写脚本
#!/bin/bash
#从文件中获取变量值,$()表示调用命令执行的结果
for name in $(cat name.txt)
do
echo "$name"
done
cat name.txt //查看文件内容,只有3行
bash fen1.sh //运行脚本,显示5行内容
变量IFS定义的分隔符中有空格,for从文件中获取变量值时,以空格作为了分隔符,将"zhang san"分隔成了两行,"wang wu"也是如此。
在脚本中,先临时将变量IFS的值中的空格删除,使for语句不以空格作为分隔符,最后还原变量值。
vim fen2.sh //写脚本
#!/bin/bash
#借用一个临时变量先保存IFS的原始值
IFS_OLD=$IFS
#删除空格和制表符,只保留换行符作为分隔符
IFS=$'\n'
#从文件中获取变量值,$()表示调用命令执行的结果
for name in $(cat name.txt)
do
echo "$name"
done
#还原变量IFS的原始值
IFS=$IFS_OLD
while循环应用示例
批量添加用户
用户名称以stu开头,按数字顺序进行编号
一共添加20个用户,即stu1、stu2、...... 、stu20
初始密码均设为123456
vim while01.sh //创建脚本
#!/bin/bash
#用户名称以stu开头,按数字顺序进行编号
#一共添加20个用户,即stu1、stu2、...... 、stu20
#初始密码均设为123456
a=1
while [ $a -le 20 ]
do
useradd stu$a -M
echo "123456"| passwd --stdin stu$a &>/dev/dull
let a++
#一定要有变量迭代的过程
done
猜商品价格游戏
vim while02.sh //创建脚本
#!/bin/bash
# 猜商品价格游戏
# 通过变量RANDOM获得随机数
# 提示用户猜测并记录次数,猜中后退出循环
#-----------------------------------------
#商品价格
price=$[RANDOM%100+1]
#猜的次数
a=0
#死循环,一直为真。需要人为设置退出。
while true
do
read -p "请猜测商品价格(1-100):" num
let a++
if [ $num -eq $price ]
then
echo "恭喜你猜对了"
echo "你一共猜了 $a 次"
exit
#猜对价格后,退出脚本进程
elif [ $num -lt $price ]
then
echo "太低了"
else [ $num -gt $price ]
echo "太高了"
fi
done
while和read结合 读取文件内容
read 每次只能读取一行内容,如果read识别到了换行符,就结束这一次的读取。
linux中的换行符是:换行+回车( 即“\n” )
把test文件重定向输入给while,之后read逐行读取
while read line
do
echo $line
done < test.txt
把文件内容通过管道符传给while,之后read逐行读取
#!/bin/bash
#把文件内容通过管道符传给while,之后read逐行读取
cat test.txt | while read line
do
echo $line
done
until循环语句
重复测试某个条件,只要条件不成立则反复执行。
格式:
vim until01.sh //写脚本
#!/bin/bash
# 计算1到10的和
sum=0
i=1
# 条件不成立才执行命令序列
until [ $i -gt 10 ]
do
let sum=$[sum+i]
let i++
done
echo "1到10的求和结果是:$sum"
为指定用户发送在线消息
为指定用户发送在线消息;
若用户不在线(未登录系统),则每10分钟试一次,直至用户登录系统后再发送消息;
用户名与消息通过位置参数传递给脚本。
vim until02.sh
#!/bin/bash
#为指定用户发送在线消息
#若用户不在线(未登录系统),则每10分钟试一次,直至用户
登录系统后再发送消息
#用户名与消息通过位置参数传递给脚本
# 只要用户在线不成立(即用户不在线).就执行命令序列
until who |grep "$1" &> /dev/null
do
echo "$1 不在线"
sleep 600
done
echo $2 | write $1