shell脚本练习
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell脚本练习相关的知识,希望对你有一定的参考价值。
这篇文章主要介绍shell编程的实例
一、逻辑判断之if语句
1.判断年龄?
[[email protected] 9_1 ]#cat iftest.sh
#!/bin/bash
read -p "Please input your age:" age
## 判断用户输入的必须是数字
if [[ "$age" =~ ^[0-9]+$ ]];then
true
else
echo "Please input digit"
exit 10
fi
## 判断用户的年龄,并输出相应的信息
if [ "$age" -ge 0 -a $age -le 18 ];then
echo "good good study,day day up"
elif [ "$age" -gt 18 -a $age -le 60 ];then
## 由于前面已经判断为数字,并且为正整数,所以的 "$age" -gt 18 可以省略;
echo "work hard"
elif [ "$age" -gt 60 -a $age -le 120 ];then
## 同理,这里的"$age" -gt 60也可以省略,优化
echo "enjoy your life"
else
echo "you don not come from the earch"
fi
2.如何判断yes或no?
思路1:
1.用户输入的所有选择:y|yes|Y|YES,同n|no|N|NO
2.统一判断为大写或者小写:tr进行转换
3.使用两种选择判断:2:使用正则匹配y|yes;n|no或者大写
#!/bin/bash
read -p "Input yes or no:" answer
ans=`echo "$answer"|tr ‘A-Z‘ ‘a-z‘`
if [ "$ans" = "yes" -o "$ans" = "y" ];then
echo "YES"
elif [ "$ans" = "no" -o "$ans" = "n" ];then
echo "NO"
else
echo "Please input yes or no"
fi
思路2:使用正则进行判断
#!/bin/bash
read -p "Input yes or no:" answer
if [[ "$answer" =~ ^[Yy]([Ee][Ss])?$ ]];then
echo YES
elif [[ "$answer" =~ ^[Nn][Oo]?$ ]];then
echo "NO"
else
echo "Please input yes or no"
fi
4.判断是否富有或帅气?
[[email protected] 9_1 ]#vim yesorno2.sh
#!/bin/bash
read -p "Are you rich? yes or no: " answer
if [[ "$answer" =~ ^[Yy]([Ee][Ss])?$ ]];then
echo OK
elif [[ "$answer" =~ ^[Nn][Oo]?$ ]];then
read -p "Are you handsome? yes or no: " answer
if [[ "$answer" =~ ^[Yy]([Ee][Ss])?$ ]];then
echo Ok
exit
elif [[ "$answer" =~ ^[Nn][Oo]?$ ]];then
echo "work hard"
else
echo "Please input yes or no"
fi
else
echo "Please input yes or no"
fi
二、逻辑判断之case语句
1.判断数字
[[email protected] 9_1 ]#vim casetest.sh
#!/bin/bash
read -p "Please input a digit: " num
case $num in
1|2|3)
echo 1,2,3
;;
4|5|6)
echo 4,5,6
;;
7|8|9)
echo 7,8,9
;;
*)
echo other digit
;;
esac
2.判断yes|no
#!/bin/bash
read -p "Please input yes or no: " ans
case $ans in
[Yy]|[Yy][Ee][Ss])
echo YES
;;
[Nn]|[Nn][Oo])
echo NO
;;
*)
echo input false
;;
esac
3.打印菜单:
[[email protected] ~ ]#cat menu.sh
#!/bin/bash
cat <<EOF
1:lamian
2:huimian
3:daoxiaomian
4:junbing
5:mifan
EOF
read -p "Please choose the number: " num
case $num in
1)
echo "lamian price is 15"
;;
2)
echo "huimian price is 18"
;;
3)
echo "daoxiaomian price is 13"
;;
4)
echo "junbing price is 10"
;;
5)
echo "mifan price is 2"
;;
*)
echo "INPUT false"
esac
效果:
[[email protected] ~ ]#sh menu.sh
1:lamian
2:huimian
3:daoxiaomian
4:junbing
5:mifan
Please choose the number: 5
mifan price is 2
三、循环之for循环
help for————两种语法
语法1:
for NAME [in WORDS ... ] ; do COMMANDS; done
语法2:
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
[[email protected] 9_2 ]#for num in 1 2 3 4 5;do echo "num=$num"; done
num=1
num=2
num=3
num=4
num=5
1.不断追加求和
[[email protected] 9_2 ]#sum=0; for num in 1 2 3 4 5; do sum=$[sum+num];done ;echo sum=$sum
sum=15
2.求1+2+3+..+100的和 (面试题)
方法1: {1..100}生成序列
[[email protected] 9_2 ]#sum=0; for num in {1..100}; do sum=$[sum+num];done ;echo sum=$sum
sum=5050
## 用于计算的方式有$[] 和$(())以及let等等。
方法2:seq 100生成序列
[[email protected] 9_2 ]#sum=0; for num in `seq 100`; do sum=$[sum+num];done ;echo sum=$sum
sum=5050
2.1 求1+2+3+..+100以内所有奇数的和|所有偶数的和?
奇数之和:
[[email protected] ~ ]#sum=0; for num in {1..100..2}; do sum=$[sum+num];done ;echo sum=$sum
sum=2500
[[email protected] ~ ]#sum=0; for num in `seq 1 2 100`; do sum=$[sum+num];done ;echo sum=$sum
sum=2500
偶数之和:
[[email protected] ~ ]#sum=0; for num in {2..100..2}; do sum=$[sum+num];done ;echo sum=$sum
sum=2550
[[email protected] ~ ]#sum=0; for num in `seq 2 2 100`; do sum=$[sum+num];done ;echo sum=$sum
sum=2550
2.2 打印奇数和偶数的几种方法?
[[email protected] 9_2 ]#seq 1 2 10————打印奇数
1
3
5
7
9
[[email protected] 9_2 ]#seq 2 2 10————打印偶数
2
4
6
8
10
[[email protected] 9_2 ]#seq 1 10 |sed -n "1~2p" ——————sed打印奇数
1
3
5
7
9
[[email protected] 9_2 ]#seq 1 10 |sed -n "2~2p"————————sed打印偶数
2
4
6
8
10
[[email protected] ~ ]#echo {1..10..2} ————————————————{}也可以实现输出奇数
1 3 5 7 9
[[email protected] ~ ]#echo {2..10..2} ————————————————{}打印偶数
2 4 6 8 10
3.练习:如何实现批量执行一个目录下的所有脚本?————(前提:所有文件都拥有x权限,并且是非交互式的)
[[email protected] 9_2 ]#ls
case_yesorno.sh test.sh
[[email protected] 9_2 ]#
[[email protected] 9_2 ]#for filename in *.sh;do ./$filename;done
Please input yes or no: yes
YES
hello,world
4.练习:批量创建user1..10的用户,并设置密码为magedu,设置首次登录更改密码?
[[email protected] 9_2 ]#vim createuser_n.sh
#!/bin/bash
for num in {1..10};do
useradd user${num}
echo "magedu" |passwd --stdin user${num} &> /dev/null
passwd -e user${num} &> /dev/null
done
5.练习:编写一个×××扫描器,实现扫描一个网段(1-254)中那些主机是开机的?
## 默认是顺序执行,ping完一个ip后再ping下一个,那么可不可以并行执行?
[[email protected] 9_2 ]#cat scanip.sh
#!/bin/bash
## 每次执行前清空文件
> /data/iplist.log
net=172.20.129
for i in {1..254};do
## 添加{}实现并行执行
{ if ping -c1 -W1 $net.$i &> /dev/null ;then
echo $net.$i is up
echo $net.$i >> /data/iplist.log ## 注意这里是追加,所以在脚本开始清空文件
else
echo $net.$i is down
fi } & ## 前后对应,并放入后台执行
done
wait ## 由于需要手动按enter退出,所以添加wait命令自动退出
优化版:交互式输入
[[email protected] 9_2 ]#vim scanip.sh
#!/bin/bash
> /data/iplist.log
## 交互式输入
read -p "Please input the network:(eg:192.168.0.0):" net
## 截取前三段,否则出现1.1.1.0.249情况
net=`echo $net|cut -d. -f1-3`
for i in {1..254};do
{ if ping -c1 -W1 $net.$i &> /dev/null ;then
echo $net.$i is up
echo $net.$i >> /data/iplist.log
else
echo $net.$i is down
fi } &
done
wait
6.练习:写一个计算网络ID的netid.sh,ip地址和子网掩码做与运算,如下所示:
[[email protected] 9_2 ]#echo $[193&240]
192
[[email protected] 9_2 ]#cat netid.sh
#!/bin/bash
read -p "input a ip: " ip
read -p "input a netmask: " netmask
## 每次cut取一个字段,然后循环4次
for i in {1..4};do
net=`echo $ip |cut -d. -f$i`
mask=`echo $netmask |cut -d. -f$i`
if [ $i -eq 1 ];then
## 先一个字段与另外一个字段相与,最后再进行组合
netid=$[net&mask]
else
netid=$netid.$[net&mask]
fi
done
echo netid=$netid
优化版:
[[email protected] 9_2 ]#cat netid.sh
#!/bin/bash
read -p "input a ip: " ip
read -p "input a netmask: " netmask
for i in {1..4};do
net=`echo $ip |cut -d. -f$i`
mask=`echo $netmask |cut -d. -f$i`
subnetid=$[net&mask]
if [ $i -eq 1 ];then
netid=$subnetid
else
netid=$netid.$subnetid
fi
done
echo netid=$netid
其他参考:
[[email protected] 9_2 ]#cat netid1.sh
#!/bin/bash
read -p "input a ip: " ip
read -p "input a netmask: " netmask
for (( i = 1; i < 5; i++ ));do
ip1=`echo $ip |cut -d. -f$i`
netmask1=`echo $netmask |cut -d. -f$i`
echo -n $[$ip1&$netmask1] ## 用-n实现不换行追加
if [ $i -eq 4 ];then ## 每次输出一个网络id字段后并输出一个点,然后不断追加
echo ""
else
echo -n "."
fi
done
[[email protected] 9_2 ]#
7.练习:通过交互式的方式输入行数和列数,打印出矩形?
[[email protected] 9_2 ]#cat rectangle.sh
#!/bin/bash
read -p "input line number: " x
read -p "input colume number: " y
for row in `seq $x`;do ## 指定行数打印多行
for col in `seq $y`;do ## 通过指定列数打印一行
echo -e "*c"
done
echo ## 每一行打印完后换行
done
优化版:添加颜色显示,并闪烁
[[email protected] 9_2 ]#cat rectangle.sh
#!/bin/bash
read -p "input line number: " x
read -p "input colume number: " y
for row in `seq $x`;do ## 指定行数打印多行
for col in `seq $y`;do ## 通过指定列数打印一行
color=$[RANDOM%7+31] ## RANDOM%7表示0-6,+31即31-37
echo -e " 33[1;5;${color}m* 33[0mc" ## 1高亮显示,5闪烁,c换到行尾表示不换行
done
echo ## 每一行打印完后换行
done
[[email protected] 9_2 ]#
8.练习:打印等腰三角形
利用for的第二种语法实现
[[email protected] 9_4 ]#cat fortriangle.sh
#!/bin/bash
read -p "Please input a line number: " line
for ((i=1;i<=line;i++));do
for ((j=1;j<=$[line-i];j++));do
echo -n " "
done
for ((k=1;k<=$[2*i-1];k++));do
echo -n "*"
done
echo
done
9.打印九九乘法表
方法1:
[[email protected] 9_4 ]#vim multi.sh
#!/bin/bash
for i in {1..9};do ## 外层循环决定了打几行,i相当于行号
for j in `seq $i`;do ## j表示其中的一行循环多少遍?
echo -e "$j*$i=$(($j*$i)) c" ## 计算$j*$i的结果,并以tab分隔,不换行;
done
echo ## echo的位置表示打印一行后进行换行;
done
[[email protected] 9_4 ]#sh multi.sh
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
思路:找规律,第一个数字是列编号 第二个数字是行号;
先打印一行 ,然后循环打印多行————————打印一行的时候,需要计算循环多少遍?——————最终发现由行号决定循环几遍
方法2:C语言风格
[[email protected] 9_4 ]#cat for_mult.sh
#!/bin/bash
for ((i=1;i<=9;i++));do
for ((j=1;j<=i;j++));do
echo -e "$j*$i=$[j*i] c"
done
echo
done
10.在/testdir目录下创建10个html文件,文件名格式为数字N(从1到10)加随机8个字母,如:1AbCdeFgH.html
[[email protected] 9_4 ]#vim create.sh
#!/bin/bash
for i in {1..10};do
touch $i`tr -dc "0-9a-zA-Z" < /dev/urandom|head -c8`
done
四、循环之while循环
1.练习:计算1+2+3+..+100的和
[[email protected] 9_4 ]#vim while.sh
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ];do
let sum+=i
let i++
done
echo sum=$sum
"while.sh" [New] 8L, 86C written
[[email protected] 9_4 ]#sh while.sh
sum=5050
2.练习:九九乘法表
9_4 ]#vim whilemult.sh
#!/bin/bash
i=1
while [ $i -le 9 ];do
j=1
while [ $j -le $i ];do
echo -e "$j*$i=$[$j*$i] c"
let j++
done
echo
let i++
done
[[email protected] 9_4 ]#sh whilemult.sh
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=
3. 练习:打印等腰三角形
[email protected] 9_4 ]#cat while_triangle.sh
#!/bin/bash
read -p "Please input a line number: " line
i=1 ## 打印多行
while [ "$i" -le "$line" ];do
## print space ## 打印空格
j=1
while [ "$j" -le $[line-i] ];do
echo -n " " ##或者使用 echo -e " c"
let j++
done
## print * ## 打印*的个数
k=1
while [ "$k" -le $[2*i-1] ];do
echo -n "*"
let k++
done
let i++
echo
done
[[email protected] 9_4 ]#sh while_triangle.sh
Please input a line number: 10
*
***
*****
*******
*********
***********
*************
***************
*****************
*******************
思路:先打出空格——————再打印*的个数
定义总行数:line
当前行:i
当前列:j中间 所在列=总行数line
当前行从开头到中间 的个数=i
space=line-i
当前行 的个数=2i-1
4.练习:监控httpd服务的状态?
#!/bin/bash
SLEEPTIME=10
while : ;do ## :和true都表示为真
if killall -0 httpd &> /dev/null ;then ## kill -0 表示监控进程是否在运行
true
else
service httpd restart
echo "At `date +‘%F %T‘` httpd restart" >> /var/log/checkhttpd.log
fi
sleep $SLEEPTIME ## 等待时间
done
##建议使用nohup script & 放入后台执行,终端的退出将不影响执行。
5.练习:编写脚本,利用变量RANDOM生成10个随机数字,输出这个10数字,并显示其中的最大值和最小值
[[email protected] 9_4 ]#cat formaxmin.sh
#!/bin/bash
echo -e "random list:c"
for ((i=0;i<10;i++));do
rand=$RANDOM
echo -e " $randc"
if [ $i -eq 0 ];then ## 第一次的随机数字没有可比的数字,所以既是最大值又是最小值;
max=$rand
min=$rand
fi
if [ $max -lt $rand ];then ## 如果随机数大于最大值,则rand替换为最大值;
max=$rand
elif [ $min -gt $rand ];then ## 否则为假,即随机数<max,并且<min,则替换为最小值。
min=$rand
else
true ## 如果是其他情况,则默认
fi
done
echo
echo max is $max
echo min is $min
效果如图:
[[email protected] 9_4 ]#sh formaxmin.sh
random list: 18428 5303 6933 16210 2577 4107 23750 16836 3435 14399
max is 23750
min is 2577
五、循环之until循环
注意:为真,退出
为假,则执行循环语句
1.练习:查看系统登录用户,如果有hacker这个登录用户,则踢出去?
[[email protected] 9_4 ]#cat untiltest.sh
#!/bin/bash
until who|grep -q "^hacker>";do
sleep 3
done
## 如果有hacker用户在登录,则退出脚本,并执行下面的pkill语句。
pkill -9 -U hacker ## 注意 pkill -9 可以杀死用户所有的进程。
## 优化版:不退出脚本,进入死循环,hacker一旦登录,则直接踢出去
[[email protected] 9_4 ]#cat untiltest.sh
#!/bin/bash
until false; do ## 为假则进入死循环
who|grep -q "^hacker>" && pkill -9 -U hacker
sleep 3
done
其他小练习
1.练习:随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出
#!/bin/bash
rand=$[RANDOM%11] ## 生成0-10的随机数字
while read -p "input a number: " num;do
if [[ ! $num =~ ^[0-9]+$ ]];then ## 由于直接比较,不是>
数字的话会报错,所以进行判断;
echo "Please input a digit"
continue ## 结束本次循环
elif [ $num -gt $rand ];then
echo $num is greater
elif [ $num -lt $rand ];then
echo $num is little
else
echo "guess OK"
break ## 退出整个循环
fi
done
2.练习:逐行读取df的信息,然后判断分区的利用率是否大于8,大于则进行提示
方法1:
[[email protected] 9_4 ]#cat diskcheck.sh
#!/bin/bash
df |sed -n "/sd/p"|while read line;do
name=`echo $line |tr -s " " %|cut -d% -f1` ## 通过echo $line对读取到的每一行进行处理
used=`echo $line |tr -s " " %|cut -d% -f5`
if [ $used -gt 8 ];then
echo "$name will be full;$used %"
fi
done
[[email protected] 9_4 ]#sh diskcheck.sh
/dev/sda2 will be full;9 %
/dev/sda1 will be full;16 %
方法2:
#!/bin/bash
df |while read line;do
if [[ "$line" =~ /dev/sd.* ]];then
used=`echo $line|tr -s " " %|cut -d% -f5`
if [ $used -gt 8 ];then
echo "$line" |tr -s " " :|cut -d: -f1,5
fi
fi
done
[[email protected] 9_4 ]#sh diskcheck1.sh
/dev/sda2:9%
/dev/sda1:16%
3.练习:扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话为62985600,并提示该用户的GECOS信息修改成功?
[[email protected] 9_4 ]#cat user.sh
#!/bin/bash
while read line ;do
GECOS=`echo $line|cut -d: -f5`
USER=`echo $line|cut -d: -f1`
[ -z "$GECOS" ] && chfn -f $USER -p 2985600 $USER &> /dev/null;
done < /etc/passwd
4.练习: ss -nt查看访问连接的ip,如果达到两个,就设置防火墙策略拒绝连接。
[[email protected] 9_4 ]#vim test.sh
#!/bin/bash
ss -nt|sed -nr ‘/ESTAB/s/.* (.*):.*/1/p‘|sort|uniq -c|while read line;do ## 取出ip并统计次数,然后逐行读取;
IP=`echo $line|cut -d" " -f2`
num=`echo $line|cut -d" " -f1`
if [ "$num" -ge 2 ];then
iptables -A INPUT -s $IP -j REJECT ## 如果连接数>2,则使用防火墙策略阻止连接
else
true
fi
done
5.select菜单
语法:select: select NAME [in WORDS ... ;] do COMMANDS; done
[[email protected] ~ ]#cat select.sh
#!/bin/bash
PS3="please choose a digit: " ## PS3专门用来提供输入
select MENU in jiaozi lamian mifan daoxiaomian quit;do ## in后面的参数默认按照序号1 2 3 4等一一对应;
case $MENU in
jiaozi)
echo "Your choose is $REPLY" ## 变量REPLY专门用于存储用户输入的结果
echo "$MENU price is 20"
;;
lamian)
echo "Your choose is $REPLY"
echo "$MENU price is 15"
;;
mifan)
echo "Your choose is $REPLY"
echo "$MENU price is 18"
;;
daoxiaomian)
echo "Your choose is $REPLY"
echo "$MENU price is 12"
;;
quit)
echo "Your choose is $REPLY"
break
;;
*)
echo "Your choose is $REPLY"
echo "choose again"
;;
esac
done
效果:
[[email protected] ~ ]#sh select.sh
1) jiaozi
2) lamian
3) mifan
4) daoxiaomian
5) quit
please choose a digit: 1
Your choose is 1
jiaozi price is 20
please choose a digit: 2
Your choose is 2
lamian price is 15
please choose a digit: 5
Your choose is 5
以上是关于shell脚本练习的主要内容,如果未能解决你的问题,请参考以下文章