1 shell脚本基础知识
1.1 目录
- 函数及实战
- 函数的语法
- 函数的执行
- 函数实战
- for循环语句及实战
- for循环语法结构
- for循环案例实战
- while和until循环语句及实战
- while循环语法结构
- until循环语法结构
- while循环和until循环的区别
- while循环按行读取文件的方法总结
- while循环案例实战
- select 循环语句及实战
- select循坏语法结构
- select循坏案例实战
- 循环控制及状态返回值实战
- break、continue、exit、return
- 数组及实战
- 什么是shell数组
- 数组的定义
- 数组的调用
- 数组的打印及输出
- 数组案例实战
1.2 函数及实战
1.2.1 函数的语法
方法一:
function 函数名()
{
函数体
}
方法二:
函数名()
{
函数体
}
1.2.2 函数的执行
1.无参数函数
函数名
2.有参数函数
函数名 参数1 参数2 .....
注:函数参数类似于shell脚本的位置参数,$1-$2分别表示提供给函数的第1个参数到第n个参数
$# 参数个数
$@和$* 为所有参数列表
$0仍为父脚本的名称
1.2.3 函数实战
案例描述:编写脚本模拟用户密码登录(用户名和密码只能是tom/123),要求:编写input函数:用于判断用户的输入是否为空
思路分析:
1.环境准备
2.解决思路
1)编写输入函数,结合while实现
2)提示输入用户名,如果用户名不是tom,则提示“用户不存在”
否则,提示用户输入密码,如果密码不是123,则提示“密码错误,请重新输入”
否则,提示“登录成功”
3.开发脚本
#!/bin/bash
#Author:ZhangMiaomiao
#Blog:http://blog.youkuaiyun.com/moledyzhang
#Time:2017-10-10 21:27:24
#Name:login.sh
#Version:V1.0
#Description:
fun_input()
{
input=""
while [ -z $input ]
do
read -p "$1" input
done
echo $input
}
username=`fun_input 请输入用户名:`
if [ $username = "tom" ];then
password=`fun_input 请输入密码:`
if [ $password != "123" ];then
echo "密码错误,请重新输入"
else
echo "登录成功"
fi
else
echo "该用户不存在"
fi
执行结果:
1.3 for循环语句及实战
1.3.1 for循环语法结构
1.第一种:变量取值型for循环
for 变量名 in 变量值列表
do
循环体
done
2.第二种:c语言型for循环
for((exp1,exp2,exp3))
do
循环体
done
1.3.2 for循环案例实战
1.输出数字系列 1 2 3 4 5
方法一:直接列出元素法
for i in 1 2 3 4 5
do
echo $i
done
方法二:使用{}
for i in {1..5}
do
echo $i
done
方法三:使用seq命令
注:"seq m n" 命令用于产生一个数到另一个数之间所有的整数
for i in `seq 1 5`
do
echo $i
done
2.批量创建用户tom01到tom10,并设置随机密码(要求为字母和数字的8位组合)
案例分析:
1.环境准备:无
2.思路分析
1).产生数字01到10的方法
方法一:seq -w 01 10
方法二:echo {01..10}
2).创建用户
useradd 用户名 3).设置无交互密码的方法
echo 密码|passwd --stdin 用户名
4).产生随机密码的方法
echo $RANDOM|md5sum|cut -c 3-10
3.开发脚本
user="tom"
passwfile="/tmp/user.log"
for i in `seq -w 01 10`
do
useradd $user$i #创建用户
passw=`echo $RANDOM|md5sum|cut -c 3-10 ` #因多次使用随机数,所以定义变量保存
echo $passw|passwd $user$i --stdin &>/dev/null #设置密码
echo -e "user:$user$i\tpasswd:$passw">>$passwfile #保存设置的账号和密码信息
done
cat $passwfile
执行结果:
1.4 while和until循环语句及实战
1.4.1 while循环语法结构
while <条件表达式>
do
循环体
done
条件表达式的位置写true表示条件永远为真
1.4.2 until循环语法结构
until <条件表达式>
do
循环体
done
1.4.3 while循环和until循环的区别
while循环是满足条件进入循环
until循环是满足条件则退出循环
1.4.4 while循环按行读取文件的方法总结
方法一:利用for循环和cat结合
for line in `cat FILE`
do
echo $line
done
方法二:使用cat读取文件,然后通过管道进入while循环处理
cat FILE|while read line
do
操作
done
方法三:在while循环结尾done处通过输入重定向指定读取的文件
while read line
do
操作
done < FILE
方法四:采用exec读取文件,然后进入while循环处理
exec < FILE
while read line
do
echo $line
done
1.4.5 while循环案例实战
案例描述:编写一个案例解决防止DDoS攻击的生产案例。请根据web日志或系统连接数,监控某个ip的并发连接数,若短时间内pv达到100,即封掉对应的ip
防火墙命令为:iptables -I INPUT -s IP -j DROP
案例分析:
方法一:分析web日志(这里按每小时为单位进行处理)(实际应用应该根据公司网站业务)
1.环境准备
1)安装nginx
2)日志切割,将日志分成不同的文件
2.分析思路-转换对应的代码
1)分析访问日志,将ip及对应的次数存入文件
awk '{print $1}' /usr/local/nginx/logs/access.log|grep -v '^$'|sort|uniq -c>/tmp/tmp.log
2)分析文件中的每一行,如果超过100次则封掉
3.开发脚本
file=$1
awk '{print $1}' $1|grep -v '^$'|sort|uniq -c>/tmp/tmp.log #分析切割后的日志将ip及对应次数存入临时文件
exec</tmp/tmp.log
while read line
do
ip=`echo $line|awk '{print $2}'`
num=`echo $line|awk '{print $1}'`
if [ $num -gt 100 ] && [ `iptables -L -n|grep "$ip"|wc -l` -lt 1 ];then #封掉大于100次的ip
iptables -s $ip -p tcp -I INPUT -j DROP
echo "$ip is dropped ">/tmp/drop_ip_list_$(date +%F).log #记录处理日志
fi
done
执行结果:
方法二:分析网络连接数
#!/bin/bash
check_ddos(){
netstat -antu|grep ESTABLISHED|awk -F '[ :]+' '{print $6}'|sort|uniq -c > ESTABLISHED.log
[ $? -eq 0 ]&&exec < ESTABLISHED.log||exit 1
while read line
do
pv=`echo $line|awk '{print $1}'`
ip=`echo $line|awk '{print $2}'`
if [ $pv -gt 100 ]&&[ `/etc/init.d/iptables -L -n|grep $ip|wc -l` -gt 0 ];then
iptables -I INPUT -s $ip -j DROP
fi
done
}
main(){
while true
do
check_ddos
sleep 3m
done
}
main
1.5 select 循环语句及实战
1.5.1 select循环语法结构
select 变量名 [in 菜单值列表]
do
循坏体
done
1.5.2 select循环案例实战
案例描述:打印选择菜单,安装选择一键安装不同的服务,菜单效果如下:脚本:
select var in "Install lamp" "Install lnmp" "exit"
do
case $var in
"Install lamp")
echo "starting install lamp";;
"Install lnmp")
echo "starting install lnmp";;
"exit")
echo "Bye"
exit;;
*)
echo "input error,must be input {1|2|3}";;
esac
done
1.6 循环控制及状态返回值实战
1.6.1 break、continue、exit、return对比
1.7 数组及实战
1.7.1 什么是shell数组
简单说,shell数组就是一个元素集合,它把有限个元素(变量或字符内容)用一个名字来命名,然后对它们进行区分。这个名字就是数组名,用于区分不同内容的编号就被称为数组的下标或索引。组成数组的每个变量或字符被称为数组的元素。
1.7.2 数组的定义
方法一:
数组名=(值1 值2 值3…)
例子
array=(tom jack rose)空格隔开的字符串依次赋值给数组每个元素
array=([0]=tom [1]=jack [2]=rose [6]=natasha)
方法二:
array=([1]=tom [2]=lucy [3]=alice)
方法三:(下标可以不连续)
array[0]="tom"
array[1]="jack"
array[2]="rose"
array[6]="natasha" 注:7个元素0-6,中间未赋值的为空
1.7.3 数组的调用
${数组名[下标值]}
在数组中可以使用*或@符号来代替下标,此时*或@为通配符,所以可以用array[*]或array[@]数组中的所有元素
数组中元素个数:${#array[*]}或者${#array[@]} 注:是非空元素个数
数组中单个元素的长度:${#array[n]},其中n为元素下标
1.7.4 数组的打印及输出
1.打印数组元素
3.数组中元素的删除
4.数组内容的截取和替换 截取
删除数组元素部分内容
5.数组的删除
1.7.5 数组案例实战
案例描述:使用数组方法打印下面这段话中单词数不大于6的所有单词
i am a bw teacher welcome to beijing bw
1.解决思路:
1).先将所有单词存入数组 array=(i am a bw teacher welcome to beijing bw)
2).计算数组中每个元素的长度
3).如果不大于6则打印该单词
2.开发代码:
array=(i am a bw teacher welcome to beijing bw)
for word in ${array[*]}
do
if [ ${#word} -lt 6 ];then
echo $word
fi
done
执行结果: