if选择结构
if单分支处理:当“条件成立”时执行命令序列xx,否则,不执行任何操作(只判断为真)
if [条件测试] ; then
命令序列xx
fi
示例:检测/media/cdrom目录,若不存在则创建
#!/bin/bash
MOUNT_DIR="/media/cdrom/"
if [ ! -d $MOUNT_DIR ] ; then
mkdir -p $MOUNT_DIR
fi
示例:每分钟判断当前登陆用户是否超过3人,若超过3人,自动发送邮件给root,报警!
#!/bin/bash
num=$(who |wc -l) #计算登陆用户
if [ $num -gt 3 ];then #判断用户是否大于3,如果大于,则发送邮件
mail -s Warning [email protected] < /root/mail.txt
mail -s Warning root < /root/mail.txt
fi
1、chmod +x test.sh
2、将脚本放到计划任务内:crontab -e
* * * * * /root/test.sh
示例:如果是管理员,执行所有命令
#!/bin/bash
if [ $USER == root ];then
yum -y install vsftpd
systemctl start vsftpd
systemctl enable vsftpd`
fi
###############################################################################
if 双分支处理:当“条件成立”时执行命令序列xx,否则,执行命令序列yy(非对即错)
if [条件测试] ; then
命令序列xx
else
命令序列yy
fi
示例:检测并判断指定的主机是否可ping通。用户输入IP地址,判断是否能ping通。能则输出ip地址up;不能则输出ip地址down。
为了节省ping测试时间,可以只发送3个测试包(-c 3)、缩短发送测试包的间隔秒数(-i 0.2)、等待反馈的超时秒数(-W 3)。
#!/bin/bash
read -p '请输入您要测试的IP地址:' ip
ping -c 2 -i 0.1 -W 2 $ip &> /dev/null
if [ $? -eq 0 ] ; then
echo "Host $ip is up."
else
echo "Host $ip is down."
fi
# chmod +x pinghost.sh
# ./pinghost.sh 192.168.4.5
示例:判断用户输入的用户名,该用户是否存在,存在则输出用户id基本信息,不存在则创建此用户
#!/bin/bash
read -p '请输入您的用户名:' user
id $user &> /dev/null 或使用useradd $user
if [ $? -eq 0 ];then
echo 用户已经创建
else
echo 用户已存在
id $user
fi
if 多分支处理:当条件1满足时,作xx处理;否则继续检查
条件2,若成立则作yy处理;否则,作zz处理
相当于多层if语句嵌套,针对多个条件分别执行不同的操作
if [条件测试1] ; then
命令序列xx
elif 条件测试2 ; then
命令序列yy
.. ..
else
命令序列zz
fi
脚本的退出状态:取决于退出前最后一条命令的 $? 值,或者“exit 整数值”指定。
示例:猜数字游戏:
#!/bin/bash
num=$[RANDOM%100]
for i in {1..10}
do
read -p "请输入一个范围在「0-99」的数字: " guess
if [ $num -eq $guess ];then
echo "你猜对了,恭喜您!!!"
echo "随机数为:$num; 您猜的数字为:$guess"
echo "恭喜,猜对了,猜了$i次"
exit
elif [ $num -lt $guess ];then
echo "您猜错了,您输入的数字比随机数大,您猜了$i次"
echo "您猜的数字为:$guess"
else
echo "您猜错了,您输入的数字比随机数小,您猜了$i次"
echo "您猜的数字为:$guess"
fi
done
示例:从键盘读取一个论坛积分,判断论坛用户等级
大于等于90 神功绝世
大于等于80,小于90 登峰造极
大于等于70,小于80 炉火纯青
大于等于60,小于70 略有小成
大于60 初学乍练
#!/bin/bash
read -p "请输入积分(0-100):" JF
if [ $JF –ge 90 ] ; then
echo "$JF 分,神功绝世"
elif [ $JF –ge 80 ] ; then
echo "$JF 分,登峰造极"
elif [ $JF –ge 70 ] ; then
echo "$JF 分,炉火纯青"
elif [ $JF –ge 60 ] ; then
echo "$JF 分,略有小成"
else
echo "$JF 分,初学乍练"
fi
# chmod +x gradediv.sh
# ./gradediv.sh
示例:输入一个分数,判断成绩分档:85-100优秀、70-84良好、低于70分不合格
#!/bin/bash
read -p '请输入您的分数(0-100):' FS
if [ $FS -ge 85 ] && [ $FS -le 100 ];then
echo “ $FS分!优秀 ”
elif [ $FS -ge 70 ] && [ $FS -le 84 ];then
echo “ $FS分!合格 ”
else
echo “ $FS分!不合格 ”
fi
示例:当运行/root/foo.sh redhat,输出为fedora;当运行/root/foo.sh fedora,输出为redhat;当没有任何参数或者参数不是 redhat 或者 fedora时,其错误输出产生以下信息: /root/foo.sh redhat|fedora
1)编写脚本代码# vim /root/foo.sh
#!/bin/bash
if [ "$1" == "redhat" ]
then
echo "fedora"
elif [ "$1" == "fedora" ]
then
echo "redhat"
else
echo "/root/foo.sh redhat|fedora" >&2
fi
另一种写法:
if [ $# == 0 ];then
echo '/root/foo.sh redhat |fedora' >&2 #为了对错误输出进行收集,可通过2>file查看
elif [ $1 == redhat ];then
echo fedora
elif [ $1 == fedora ];then
echo redhat
else
echo '/root/foo.sh redhat |fedora' >&2
fi
2)添加x执行权限# chmod +x /root/foo.sh
3) 测试提供正确参数的情况 # /root/foo.sh redhat
测试提供非预期参数的情况# /root/foo.sh ubuntu
测试不提供参数的情况 # /root/foo.sh
###############################################################################
列表式循环——给定一批对象,反复执行类似的操作(如购票者==>售票)
for循环处理
遍历/列表式循环:根据变量的不同取值,重复执行xx处理
列表式for循环结构:
for 变量名 in 值1 值2 值3 .. .. (变量名一般习惯用i)
do
命令序列($变量名)
done
示例:造数1:touch {1..10000}.txt
#!/bin/bash
for i in `seq 10000`
do
touch /tmp/$i.txt
done
示例:造数2:touch {01..10}.txt
#!/bin/bash
for i in {1..10}
do
useradd stu$i
echo 123456 | passwd --stdin stu$i &> /dev/null
echo stu$i创建成功
id test$a
done
示例:编写一个批量添加用户脚本,此脚本要求提供用户名列表文件作为参数,列表测试文件:http://classroom/pub/materials/userlist。如果没有提供参数,此脚本应该给出提示 Usage: /root/batchusers,退出并返回相应值;如果提供一个不存在的文件,此脚本应该给出提示 Input file not found,退出并返回相应值
1)编写脚本代码# vim /root/batchusers
#!/bin/bash
if [ $# -eq 0 ] ; then #判断位置变量为0个
echo ‘Usage: /root/batchusers’ >&2 #将正确信息变成错误信息
exit 1 #退出返回值为1
fi
if [ ! -f $1 ] ; then #文本不存在为真
echo ‘Input file not found’ >&2 #将正确信息变成错误信息
exit 2 #退出返回值为2
fi
for name in $(cat $1) # $1为文件,cat $1可以显示为文本参数,$()传递参数
do
useradd -s /bin/false $name
done
2)添加x执行权限# chmod +x /root/batchusers
3)测试batchusers批量添加用户脚本
下载用户列表测试文件:
# wget http://classroom/pub/materials/userlist -O /root/userlist
# cat /root/userlist //检查下载文件
实现批量添加用户:# /root/batchusers /root/userlist
# id duanwu
测试其他异常处理:
# /root/batchusers //未提供列表文件, Usage: /root/batchusers
# /root/batchusers /root/userlist.txt //提供的列表文件找不到,Input file not found
# echo $? //返回2
###############################################################################
作业:
根据输入成绩的分数 输出不同的提示信息
把指定的文件备份到指定的目录下
判断用户从键盘输入的数据是偶数还是奇数?
计算用户输入1-10之间的任意一个数的平方值,不输入数字的时候给出错误提示信息。
###############################################################################
循环结构
在Shell脚本应用中,常见的for循环采用遍历式、列表式的执行流程,通过指定变量从值列表中循环赋值,每次复制后执行固定的一组操作。
for循环的语法(格式1)
for 变量名 in 值列表
do
命令序列
done
示例:批量添加用户帐号(名称没有规律)
素材:/root/users.txt
#!/bin/bash
ULIST=$(cat /root/users.txt)
for UNAME in $ULIST
do
useradd $UNAME 2>/var/err/log
echo "123456" | passwd --stdin $UNAME > /dev/null
done
# chmod +x uaddfor.sh
# ./uaddfor.sh
示例:使用循环ping测试网络中所有主机
#!/bin/bash
net=192.168.4.
for i in `seq 1 254` #反引号 //{1..254}
do
ping -c 3 -i 0.2 -w 0.2 $net$i &>/dev/null
if [ $? -eq 0 ];then
echo "该主机$net$i,ping通"
else
echo "该主机$net$i,无法ping通"
fi
done
C语言风格的for循环(格式2)
通过变量控制,条件成立时循环;步长可控次数
for ((初值;条件;步长控制))
do
命令序列
done
#!/bin/bash
for ((i=1;i<=5;i+=2)) //或for ((i=1;i<=5;i++))
do
echo $i
done
示例:制作9*9乘法表
#!/bin/bash
for ((i=1;i<=9;i++))
do
for ((j=1;j<=$i;j++))
do
echo -n "$i*$j=$((i*j))"
done
echo
done
++++++++++++++++++++++++
字体色:echo -e "\033[34mOK\033[0m"
背景色:echo -e "\033[44mOK\033[0m"
for 第一个人 in 张三 李四 王五 .. ..
do
为第一个人采血
done
for 第一个人 in $(cat 用户列表文件)
do
为第一个人采血
done
for 第一个人 in $(cat $1)
do
为第一个人采血
done
for NAME in $(cat $1)
do
useradd -s /bin/false $NAME
done
while循环格式
——条件式循环:反复测试条件,只要成立就执行命令序列
while循环属于条件式的执行流程,会反复判断指定的测试条件,只要条件成立即执行固定的一组操作,直到条件变化为不成立为止。所以while循环的条件一般通过变量来进行控制,在循环体内对变量值做相应改变,以便在适当的时候退出,避免陷入死循环。
while 条件测试
do
命令序列
done
for循环的循环次数根据值列表而固定,而while循环的循环次数不固定
+++++++++++++++++++++++++++++++++
示例:批量添加用户(名称有规律)
#!/bin/bash
PREFIX=”stu”; i=1 #定义用户名前缀
while [ $i -le 20 ]
do
useradd ${PREFIX}$i #添加的用户名为:前缀+编号
echo “123456” | passwd --stdin ${PREFIX}$i &> /dev/null
let i++ #递增控制,避免死循环
done
# chmod +x uaddwhile.sh
# ./uaddwhile.sh
# grep ^stu /etc/passwd #检查添加的用户
批量删除用户账号udelwhile.sh
将上一示例的命令改为
userdel -r ${PREFIX}$i &> /dev/null
let i++
# grep ^stu /etc/passwd //再检查已无相应账号信息
示例:检测192.168.4.0/24网段,列出不在线的主机地址
#!/bin/bash
NET="192.168.4." ; i=1
while [ $i -le 254 ]
do
IP="${NET}$i"
ping -c 3 -i 0.2 -W 1 $IP &> /dev/null
if [ $? -eq 0 ] ; then
echo "Host $IP is up."
else
echo "Host $IP is down."
fi
let i++
done
示例:猜数字
#!/bin/bash
#这是一个猜数字的游戏
biggest=10 #(代表取数据的最大值)
guess=0 #(玩家输入的数字)
guesses=0 #(输入数字的次数)
number=$(($$ % $biggest)) #random number, between 1 and $biggest,$$代表当前脚本执行的PID,可以当作以一个随机数
while [ $guess -ne $number ]
do
echo -n "Guess?" ; read guess
if [ $guess -lt $number ];then
echo "...猜小了!"
elif [ $guess -gt $number ];then
echo "...猜大了!"
fi
guesses=$(($guesses + 1))
done
echo "猜对了!!!Guessed $number in $guesses guesses."
exit 0
#echo -n 回避换行
#guess=0,定义一个变量,这里存在bug,如果guess取值为0,会出错
+++++++++++++++++++++++++++++
死循环
while : while True
do do
命令 命令
done done
+++++++++++++++++++++++++++++
示例:猜数字
#!/bin/bash
num=$[RANDOM%100+1] ;i=0
while :
do
read -p "请输入一个数字,范围为[1-100]:" guess
let i++
if [ $guess -eq $num ];then
echo “蒙对了,猜了$i次”
exit
elif [ $guess -gt $num ];then
echo “蒙大了”
else
echo “蒙小了”
fi
done
示例:点名器,屏幕随机刷人名(1-n行数)
#!/bin/bash
user=/root/users.txt
while :
do
clear
line=`cat $user |wc -l`
num=$[RANDOM%$line+1]
head -$num $user |tail -1
sleep 0.2 #加上sleep 0.2 ,这样会使cpu的使用不致过高
done
示例:写个脚本,屏幕提示如下
1.查看IP;2.查看内存;3.查看CPU信息;4.查看硬盘;5.退出
请输入您的选项[1-5]: abc
#!/bin/bash
while :
do
clear
echo -e "\033[34m 菜单\033[0m"
echo "1.查看IP
2.查看CPU
3.查看磁盘
4.查看内存
5.退出"
read -p "请输入选项[1-5]:" i
if [ $i -eq 1 ];then
ifconfig eth0 |grep "inet"
read -p "按回车键继续..."
elif [ $i -eq 2 ];then
cat /proc/cpuinfo |grep vendor
cat /proc/cpuinfo |grep MH
cat /proc/cpuinfo |grep cache
read -p "按回车键继续..."
elif [ $i -eq 3 ];then
df -h
read -p "按回车键继续..."
elif [ $i -eq 4 ];then
free
read -p "按回车键继续..."
elif [ $i -eq 5 ];then
exit
else
read -p "请输入选项[1-5]:" i
fi
done
case语句(简化版if)
——检查变量的实际取值相匹配,则执行对应的操作
case分支属于匹配执行的方式,它针对指定的变量预先设置一个可能的取值,判断该变量的实际取值是否与预设的某一个值相匹配,如果匹配上了,就执行相应的一组操作,如果没有任何值能够匹配,就执行预先设置的默认操作。
case 变量值 in
模式1)
命令序列1 ;;
模式2)
命令序列2 ;;
*)
默认命令序列
esac
示例:当用户输入参数redhat(fefora),则返回fefora(redaht),其他则提示用法
#!/bin/bash
if [ $1 == "redhat" ];then # $1为脚本执行时的第一个参数
echo "fedora"
elif [ $1 == "fedora" ];then
echo "redhat"
else
echo "用法: $0 {redhat|fedora}"
fi
或者
#!/bin/bash
case $1 in
redhat)
echo "fedora";;
fedora)
echo "redhat";;
*) #默认输出脚本用法
echo "用法: $0 {redhat|fedora}"
esac
示例:判断用户输入的是数字、字母、标点符号(击键类型)
#!/bin/bash
read -p "输入字符:" key
case $key in
[0-9])
echo 数字;;
[a-Z])
echo "字母";;
*)
echo "空格、功能键或其他控制字符"
esac
++++++++++++++++++++++++++++
编写Apache启动脚本:
#yum -y install httpd
#vim test.sh
#!/bin/bash
#给Apache启动脚本添加开机启动功能
#chkconfig: - 88 90
#chkconfig --add myhttpd
#chkconfig --list myhttpd
#chkconfig myhttpd on
#chkconfig myhttpd off
case $1 in
start)
/usr/sbin/httpd
echo "我已经启动了";;
stop)
kill `cat /var/run/httpd/httpd.pid`;; #反引号
restart)
kill `cat /var/run/httpd/httpd.pid`
sleep 1
/usr/sbin/httpd;;
status)
if [ -f /var/run/httpd/httpd.pid ];then
echo "httpd is 在运行..."
else
echo "没有running"
fi;;
*)
echo "用法是$0 {start|stop|restart|status}"
esac