[TOC]

0x00 基础案例

示例1.变量叠加与单双引i号得异同

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
x=123
y="$x"456
y=${y}789
echo -e "y=\e[1;32m $y \e[0m" #y=123456789

z='$y' # 单引号 不能引用变量 'character':表示字符串 #$y
a="$y" # 双引号 引用变量 特殊符号有特殊意义 \\ \n #123456789

b="$x"
c='"$x"' #不能被解析变量
echo -e "z=\e[1;37m '$z' $a \e[0m" #z = '$y' 123456789
echo -e "$c=\e[37;1;5m $b \e[0m" #$x = 123
WeiyiGeek.单双引号

WeiyiGeek.单双引号


示例2.五种计算方法Method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
va=$1
vb=$2
echo -e "输入的参数:$va,$vb \n"

## [] 方式,无操作符号无空格影响,括号里面的数值变量无需$
echo -e "\e[1;36m #Method 1 '$[exp]' \e[0m"
echo "va+vb=$[$va+$vb]"

## (()) 方式,无操作符号无空格影响,括号里面的数值变量无需$
echo -e "\n\e[1;35m #Method 2 '$((exr))' \e[0m"
echo "va+vb=$(($va+$vb))"

## let 方式,操作符号的变量两边无需空格,且里面的数值变量无需$
echo -e "\n\e[1;34m #Method 3 'let x=1+1' \e[0m"
let vc=$va+$vb
echo "va+vb=$vc"

## expr 方式,非常注意表达式两边的空格,里面的数值变量必须加上$
echo -e "\n\e[1;33m #Method 4 'expr 1 + 1' \e[0m"
result=`expr $va + $vb` #注意加号两边的空格
echo "va+vb=$result"

## declare 方法,操作符号两边无需空格,且里面的数值变量必须加上$
echo -e "\n\e[1;32m #Method 5 'declare -i x=1+1' \e[0m"
declare -i vd=$va+$vb
echo "va+vb=$vd"

## 自加自减
a=10; ((a++)); echo ${a} # 11
b=10; ((b--)); echo ${b} # 9
WeiyiGeek.数值计算的几种方式

WeiyiGeek.数值计算的几种方式


示例3.精密计算之小数计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
echo -e "\e[1;32m #精密计算bc\e[0m"

a=$1
b=$2
echo "bc精密计算a=:`echo "$a"|bc`"
echo -e "bc精密计算b=:`echo "$b"|bc` \n"

echo "bc精密计算a+b=:`echo "$a+$b"|bc`"
echo "bc精密计算a/b=:`echo "$a/$b"|bc`"
echo -e "bc精密计算a*b=:`echo "$a*$b"|bc`\n"

echo -e "\e[1;33m #scale设定小数精度(数值范围)\e[0m"
echo "scale设置小数3位精度a/b:`echo "scale=3;$a/$b"|bc`"
echo "scale设置小数3位精度a*b:`echo "scale=10;$a*$b"|bc`"
WeiyiGeek.

WeiyiGeek.


示例4.字符串与数组处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
string="alibaba is a great company"
echo "$string"
echo -e "获取字符串长度:${#string} \n"
echo -e "提取子字符串:${string:0:5} \n"
echo "查找子字符串alibaba:`expr index "$string" alibab`"

#数组案例
read -p "Please Input Data Array:" -a array_name
echo -e "\e[1;32mAll Array Arguments:${array_name[*]} \n"
# 取得数组元素的个数 length=${#array_name[*]}
echo -e "\e[1;36mArray Arguments Accounts:${#array_name[*]} \e[0m\n"
# 取得数组单个元素的长度
echo "array_name[1]:${array_name[1]}"
echo -e "\e[1;37mSingle Array Arguments(array_name[1]):${#array_name[1]} \e[0m\n"
WeiyiGeek.

WeiyiGeek.


0x01 语法记忆

示例1.分支与判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash
#if分支语句
read -p "Please INput A:" a
read -p "Please INput B:" b
read -p "Please INput C:" c
#单分支语句(1)
if [ $a == $b ];then
echo "a is equal to b!!"
fi

if [ $a != $b ];then
echo "a is not equal to b!!"
fi

#单分支语句(2)
if [ $c == $b ];then
echo "c is equal to b!!"
else
echo -e "c is not equal to b!!\n"
fi

#双分支语句
a=10
b=20
if [ $a == $b ]
then
echo "a is equal to b"
elif [ $a -gt $b ];then
echo "a is greater than b"
elif [ $a -lt $b ]
then
echo "a is less than b"
else
echo "None of the condition met"
fi


示例2.Case多分支语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/bash
#case 多分支语句
echo 'Input a number between 1 to 4'
echo -e 'Your number is:\c'
read aNum
case $aNum in
1) echo -e 'You select 1\n'
;;
2) echo -e 'You select 2\n'
;;
3) echo -e 'You select 3\n'
;;
4) echo -e 'You select 4\n'
;;
*) echo -e 'You do not select a number between 1 to 4'
;;
esac

#新颖的思路可以利用这个来写小脚本
option="${1}"
case ${option} in
-f) FILE="${2}"
echo "File name is $FILE"
;;
-d) DIR="${2}"
echo "Dir name is $DIR"
;;
*)
echo "`basename ${0}`:usage: [-f file] | [-d directory]"
exit 1 # Command to come out of the program with status 1
;;
esac

WeiyiGeek.

WeiyiGeek.


示例3.For循环(Circulation)语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
#For circulation Method 1
#一行一行得读取家目录总中.bash开头的文件
for FILE in $HOME/.bash*
do
echo $FILE
done

#依次输出
for t in 1 2 3 4 5
do
echo "输出第${t}个数字:$t"
done

#For Method2
sum=0
for((i=0;i<=100;i++))
do
sum=$[ $sum + $i ]
done
echo "一到一百相加得:$sum"

#批量解压缩
ls *.tar.gz >> gz.log 2>/dev/null
ls *.tgz >> gz.log 2>/dev/null
echo "正在解压缩 : Wait,Please!!"
for i in $(cat gz.log)
do
tar -zxf $i &> /dev/null
done
rm -rf gz.log

WeiyiGeek.

WeiyiGeek.


示例4.While 与 Until 语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
#while Circulation
num=0
sum=0
while [ $num -le 100 ]
do
sum=$(($sum+$num))
num=$[$num+1]
done
echo "1+2+....+100=$sum"

#Until Circulation
#输出 0 - 4
a=0
until [ ! $a -lt 5 ] #到5得时候就不成立了
do
echo $a
a=`expr $a + 1`
done
echo -e "\n"
#输出 0 - 5
b=0
until [ $b -gt 5 ] # 可以等于5
do
echo $b
b=$(($b

WeiyiGeek.

WeiyiGeek.


示例5.函数嵌套与调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/bash

# Define your function here
Hello () {
echo -e "Hello Shell Program!!\n"
}

# Invoke your function
Hello

# Return Arguments!!
funWithReturn(){
echo "The function is to get the sum of two numbers..."
echo -n "Input first number: "
read aNum
echo -n "Input another number: "
read anotherNum
echo "The two numbers are $aNum and $anotherNum !"
return $(($aNum+$anotherNum)) # 2
}
funWithReturn
# Capture value returnd by last command
ret=$?
echo "The sum of two numbers is $ret !"


#函数嵌套
# Calling one function from another
number_one () {
echo "Url_1 is http://see.edu.cn/cpp/shell/"
number_two
}
number_two () {
echo "Url_2 is http://see.edu.cn/cpp/"
}

# unset -f number_two #删除number_two函数
number_one

WeiyiGeek.

WeiyiGeek.


0x02 标准输入

示例1.命令行中输入参数,shell中使用位置参数变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
#接受 输出得参数(Arguments),位置参数num1=$1
num2=$2
echo -e "输入得参数:"
echo $num1,$num2
let num3=$num1+$num2 #Add输入得参数
echo -e "num1+num2=\e[1;35m $num3 \e[0m"
##
echo -e "\n代表所有参数的个数:"
echo -e " A total of\e[1;32m $# \e[0m Parameters" #所有参数的个数:
##
echo -e "\n整体参数:"
for i in "$*"
do
echo -e "ioutput:\e[1;31m $i \e[0m" #整体参数
done
##
echo -e "\n个体参数:"
for j in "$@"
do
echo -e "joutput:\e[1;36m $j \e[0m" #个体参数
done

WeiyiGeek.参数命令

WeiyiGeek.参数命令


示例2.标准输入和命令行输入验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash
# 实现标准输入格式验证的几种方法
read -p "Please two number:" NUM1 NUM2
function CheckNumberFormat(){
local value=$1
flag=$(echo $value | grep -E '[a-zA-Z_\.]'| wc -l) #字符输入时候也的值得参考
if [ $flag -eq 1 ];then
echo "please input Number!"
return 1
else
return 0
fi
}

function CheckNumberLength(){
local value=$1
if [ ${#value} -lt 1 -o -z ${value} -o ! -n ${value} -o "${value}" == "" ];then
echo "输入为空!"
fi
}


function CheckNumber(){
expr $1 + $2 + 0 > /dev/null
if [ $? -ne 0 ];then
echo "Input not number!"
fi
}


示例3.匹配更改文件名称思路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
# 批量更改文件名称

#方式1:
for file in $(ls *.jpg);do
mv $file $(echo ${file} | sed 's#需要改变的文件名称#.jpg#g')
done

#方式2:
ls *.jpg | awk -F ' ' '{print " mv " $0,$1".jpg"}' | bash
ls *.jpg | awk -F ' ' '{cmd="mv "$0" "$1".jpg";system(cmd)}'
#补充示例:wiz笔记图片批量改名并且高亮显示
$ ls | awk -F '.' '{cmd="dd=$(date +%Y%m%d%H%M%S)$RANDOM;echo -e \"\033[1;31m" $1 "\033[0m $dd \"; mv " $0 " $dd."$2;system(cmd)}'


#方式3:
rename "需要更改的字符串" "改成什么" 对什么文件进行修改
rename "_finished.html" ".jpg" *.html


0x03 进制随机编码

示例1.进制转换采用bc

1
2
3
4
5
6
7
8
#!/bin/bash
#进制之间的转换 B->O->D->H
read -p "Please INput NUmeric:" abc
echo -e "\e[1;33;5m 进制转换结果 \e[0m"
echo "二进制(BIN):`echo "obase=2;$abc"|bc`"
echo "八进制(OCTAL):`echo "obase=8;$abc"|bc`"
echo "十进制(DEC):`echo "obase=10;$abc"|bc`"
echo "十六进制(HEX):`echo "obase=16;$abc"|bc`"

WeiyiGeek.

WeiyiGeek.


示例2.Ascii码与进制转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
#Printf里的进制转换
exec 4<>test.txt #绑定文件描述符号
while read line<&4
do
echo -e "\e[1;37;5m 进制数据进行相互转换: \e[0m"
printf "%-10s \n" Octal-Dec-hex:
printf "%-10o" $line
printf "%-10d" $line
printf "%-10x \n" $line
done

#Printf里的Ascll编码
##Octal -> ASCLL(123456789)
echo -e "\e[1;36m Octal-> Ascll\e[0m"
for i in 60 61 62 63 64 65 66 67 70 71
do
printf "Octal=$i,Ascll=\\$i \n"
done

WeiyiGeek.printf相互转换

WeiyiGeek.printf相互转换


示例3.Shell脚本随机密码生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/bin/bash
#(方式1) /dev/urandom文件是Linux内置的随机设备文件,内容有些太随机,包括很多特殊符号
#tr -dc '_A-Za-z0-9' #将随机文件中其他的字符删除,仅保留大小写字母,数字,下划线
cat /dev/urandom | tr -dc '_a-zA-Z0-9' | head -c 12 #2hCOmV9AWAHA
</dev/urandom tr -dc '!@#$%^&*()-+=0-9a-zA-Z'| head -c14 #这样的方法值得学习
cat /dev/urandom | tr -dc '_a-zA-Z0-9!@#$%&*.' | fold -w 12 | head -1
cat /dev/urandom | tr -dc 'a-zA-Z0-9-_!@#$%^&*()_+{}|:<>?=' | fold -w 12| head -n 4 # 生成四组随机密码
.g0VvfzPooh*

#(方式2)利用上面的随机数来生成随机密码
echo $RANDOM | md5sum | cut -c 1-8
60354ab3
#(方式2)生成随机密码(字串截取版本)设置变量key,存储密码的所有可能性(密码库),如果还需要其他字符请自行添加其他密码字符
#使用$#统计密码库的长度
key="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
num=${#key}
pass='' #设置初始密码为空
#循环8次,生成8为随机密码
for i in {1..8}
do
index=$[RANDOM%num] #无论怎么变都在key长度范围内
pass=$pass${key:$index:1} #拼接字符串
done
echo $pass


#(方式3)生成随机密码(UUID版本,16进制密码)
uuidgen | cut -c 1-8
a1cb0776
uuidgen | md5sum | cut -c 1-8
70101a14


#(方式4)当前进程号生成随机密码(进程ID版本,数字密码)-并不是一定随机一个shell的终端pid
echo $$ | md5sum | cut -c 1-8
93c6b48c


#(方式5)通过openssl产生随机数
openssl rand -base64 8
R1NSJ4rZGXQ=


#(方式6)通过date方式获取随机数
date +%s%S | md5sum | cut -c 1-8
# 259f7c4a

date +%s%S | sha1sum
date +%s%S | sha512sum | cut -c 1-8
# 03663f46


0x04 批量操作

示例1.批量创建用户以及采用随机密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/env bash
# Step1.采用action函数的引用
[ -f /etc/init.d/functions ] && . /etc/init.d/functions
# Step2.判断是否是root
[ $UID -ne 0 ] && {
echo -e "\e[1;31m [+] only allow root create user \e[0m"
exit 1
}
# step3.创建主函数
function create(){
for n in {1..3};do
user=weiyi$n
random=$(echo ${RANDOM}`date +%s%S`${user})
pass="$(echo $random|md5sum|cut -f 2-9)"
useradd $user &>/dev/null && echo $pass | passwd --stdin $user &>/dev/null
RETVAL=$?
if [ $RETVAL -eq 0 ];then
action "useradd $user" /bin/true
else
action "useradd $user" /bin/false
fi
echo "$user $pass" >> ./user.txt
done
}

create

## 执行结果 ##
. add.sh
weiyi1-197e0f87
useradd weiyi1 [ OK ]
weiyi2-65f0d13f
useradd weiyi2 [ OK ]
weiyi3-7379dc89
useradd weiyi3 [ OK ]


示例2.排除A文件中每一行在B文件中存在的字符串

1
2
3
4
5
6
for i in $(cat a.txt);do  
flag=$(grep "${i}" b.txt -c);
if [ $flag -eq 0 ];then
echo ${i} >> c.txt;
fi;
done

0x05 文件读取

示例1.监测网站首页是否宕掉以及首页是否被修改
Step1.将需要监测的网站地址放入ip.txt中

1
2
3
4
5
6
7
8
cat > ip.txt <<END
192.168.100.197
192.168.100.198
192.168.100.199
192.168.100.200
192.168.100.201
192.168.100.202
END

Step2.写入一个监测函数思路就是利用网页的MD5指纹进行判断;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env bash
function check(){
cat ip.txt|while read line
do
url="http://${line}:$1/Login.do"
urlmd5=$(curl -s -m 2 ${url} | md5sum | cut -f 1 -d " ")
if [ "$urlmd5" == "6fc523910cb417d2247078125dd06782" ];then
echo "$url OK"
elif [ "$urlmd5" == "d41d8cd98f00b204e9800998ecf8427e" ];then
echo "$url Connect Fail";
else
echo "$url content change";
fi
done
}
check 30082
check 40082

#执行结果
./check.sh
http://192.168.100.197:30082/Login.do OK
http://192.168.100.198:30082/Login.do Connect Fail


示例2.绑定输入与文件读取使用while语实现的三种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash
## read input Variable
read -t 10 -p "Please Input [Accounts|Password]:" user pass
echo "输出的用户:$user"
echo "输入的密码:$pass"

## 方法1:While Read Line 绑定文件描述
echo -e "\e[1;32m 第一个文件输出\e[0m"
exec 3<>file.txt
while read line<&3
do
echo $line
done

## 方法2:Cat FILE.TXT 读取文件中每一行
echo -e "\e[1;35m 第二个文件输出\e[0m"
cat file1.txt |\
while read line
do
echo $line
done


## 方法3
export number=0
while read line
do
sed -i "3i\ pageid: ${number}" $line
let number++
done < all.md

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
while read line 
do
echo " - ${line} - "
done < ip.txt
- eth0 Link encap:Ethernet HWaddr 02:42:ac:00:00:08 -
- inet addr:172.0.0.8 Bcast:172.0.255.255 Mask:255.255.0.0 -
- UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 -
- RX packets:481 errors:0 dropped:0 overruns:0 frame:0 -
- TX packets:447 errors:0 dropped:0 overruns:0 carrier:0 -
- collisions:0 txqueuelen:0 -
- RX bytes:354214 (354.2 KB) TX bytes:74829 (74.8 KB) -
- -
- lo Link encap:Local Loopback -
- inet addr:127.0.0.1 Mask:255.0.0.0 -
- UP LOOPBACK RUNNING MTU:65536 Metric:1 -
- RX packets:56 errors:0 dropped:0 overruns:0 frame:0 -
- TX packets:56 errors:0 dropped:0 overruns:0 carrier:0 -
- collisions:0 txqueuelen:0 -
- RX bytes:5520 (5.5 KB) TX bytes:5520 (5.5 KB) -
-

WeiyiGeek.

WeiyiGeek.

示例3.读取文件中的字符串,对里面的词组进行排序及出现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/bash
eng="Making peace with what you don't have, that's what it's all about. I am a technical geek who is interested in learning computer technology."

#方式1:
echo $eng | sed -e 's#[ , . ]#\n#g' | sort | uniq -c | sort -nr #值得学习
# 2 what
# 1 you
# 1 with
# 1 who
# 1 that's
# 1 technology.
# 1 technical
# 1 peace
# 1 Making
# 1 learning


#方式2:
echo $eng | tr " " '\n' | sort | uniq -c | sort -nr


#(1)读取文件中内容,将词组中的各个字母进行排序,sed -r 使用正则匹配任意字符降序排列;
echo $eng | sed 's# ##g' | sed -r 's#(.)#\1\n#g' | sort |uniq -c | sort -rn -k1
# 13 t
# 12 e
# 12 a
# 8 n
# 8 i
# 8 h
# 7 o


#(2)采用方式2
echo $eng | grep -oE '[[:lower:]]' | sort | uniq -c | sort -rn
# 13 t
# 12 e
# 12 a
# 8 n
# 8 i
# 8 h
# 7 o

示例4.读取文件中的字符串,对里面的词组按照长度限定进行输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
eng="Making peace with what you don't have, that's what it's all about. I am a technical geek who is interested in learning computer technology."
arr=($eng)

#方式1:
for value in $eng
do
if [ ${#value} -gt 6 ];then
echo ${#value}-${value}
fi
done

#方法2:
for value in ${arr[*]}
do
if [ ${#value} -gt 6 ];then
echo ${#value}-${value}
fi
done


#方法3:
echo $eng | tr ' ' '\n'| awk '{len=length($1); if(len > 6){print len"-"$1}}'


#执行的结果
9-technical
10-interested
8-learning
8-computer
11-technology.


0x06 执行效率

示例1.评定一个算法的效率打印所用时间

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
start=$(date +%s) #start=`date +%s`,等号不能有空格,如果有空格,会被变量当成命令
for(( i = 0; i < 5; i++ ));do
echo $i >/dev/null
sleep 1
done
end=`date +%s`
diff=$(($end-$start)) #执行时间之差
echo "use times(ms):"$diff
echo "use times(ms):"$(($end-$start))


0x07 安全运维

示例1.防止rm误删操作
解决方法:建立类似回收站机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#1.建立回收站目录(此步骤可省略)
$ mkdir ~/.trash

#2.建立别名脚本
$ sudo vi /tmp/remove.sh
#!/bin/sh
#定义文件夹目录.trash
# home=$(env | grep ^HOME= | cut -c 6-)
trash="/.trash"
deltime=$(date +%Y%m%d-%H%M%S)
TRASH_DIR="${HOME}${trash}/${deltime}"
# 建立回收站目录当不存在的时候
if [ ! -e ${TRASH_DIR} ];then
mkdir -p ${TRASH_DIR}
fi
for i in $*;do
if [ "$i" = "-rf" ];then continue;fi
#定义秒时间戳
STAMP=`date +%s`
#得到文件名称(非文件夹),参考man basename
fileName=`basename $i`
#将输入的参数,对应文件mv至.trash目录,文件后缀,为当前的时间戳
mv $i ${TRASH_DIR}/${fileName}.${STAMP}
done

sudo chmod +x /tmp/remove.sh

#3.建立别名机制
$sudo vi /etc/bashrc
# User specific aliases and functions
alias rm="sh /home/user/tool/remove.sh"

source /etc/bashrc

#4.每日03:00定时执行清空隐藏目录.trash当然您也可以清理前一天删除的
0 3 * * * find ~/.trash/ -mtime +1 -delete


0x08 防火墙应用

示例1.防止web的ddos攻击与反爬虫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
# 实现要求:
# 1.根据web日志或者网络连接数,监控某个IP并发连接数或者段时间内达到PV到100,即调用防火墙封掉对应IP;

function main(){
cat access.log | awk '{print $1}' | sort | uniq -c | sort -r > a.log
exec<a.log
while read line
do
pv=$(echo $line|awk '{print $1}')
ip=$(echo $line|awk '{print $2}')

if [ $pv -gt $1 ] && [ $(iptables -L -n|grep "$ip"|wc -l) -eq 0];then
itables -A INPUT -s $ip -j DROP
fi

done
}

main 1024

0x09 字符串截取

描述: 在shell中截取字符串的常用方法,前面基础文章也将近过此处简单的做一个总结。

语法示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
${#var}   # 字符串长度
${var#*/} # 获取尾部子字符串 *号在分隔符的前面,就去掉其之前的字符 (首个 / 后的值)
${var##*/} # (最尾 / 后的值)
${var%/*} # 获取头部子字符串 *号在分隔符的前面,就去掉其之前的字符 (最尾 / 前的值)
${var%%/*} # (首个 / 前的值)
${var:start:len} # 指定从左边第几个字符开始以及子串中字符的个数
${var:start} # 从左边第几个字符开始一直到结束
${var:0-start:len} # 从右边第几个字符开始以及字符的个数
${var:0-start} # 从右边第几个字符开始一直到结束
${var/dir/path} # 表示将变量中第一个 dir 提换为 path
${var//dir/path} # 表示将变量中全部 dir 提换为 path
${file-my.txt} # 表示假如 $file 没设定,则使用 my.txt 作传回值。(空值及非空值时不作处理)
${file:-my.txt} # 表示假如 $file 没设定或为空值,则使用 my.txt 作传回值。 (非空值时不作处理)
${file+my.txt} # 表示假如 $file 设为空值或非空值,均使用 my.txt 作传回值。(没设定时不作处理)
${file:+my.txt} # 表示假如 $file 为非空值,则使用 my.txt 作传回值。 (没设定及空值时不作处理)
${file=my.txt} # 表示假如 $file 没设定,则使用 my.txt 作传回值,同时将 $file 赋值为 my.txt 。 (空值及非空值时不作处理)
${file:=my.txt} # 表示假如 $file 没设定或为空值,则使用 my.txt 作传回值,同时将 $file 赋值为 my.txt 。 (非空值时不作处理)
${file?my.txt} # 表示假如 $file 没设定,则将 my.txt 输出至 STDERR。 (空值及非空值时不作处理)
${file:?my.txt} # 表示假如 $file 没设定或为空值,则将 my.txt 输出至 STDERR。 (非空值时不作处理)

总结说明:

1
2
3
4
#        删除最小的匹配前缀
## 删除最大的匹配前缀
% 删除最小的匹配后缀
%% 删除最大的匹配后缀

示例演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
# Description: Shell总字符串截取总结.
str="https://blog.weiyigeek.top/about/me"
# 原字符串输出
echo "string: [${str}]"
# 获得字符串的长度
length=${#str}; echo "length: [${length}]"
# 获得尾部字符串,分割符为'/'
substr=${str#*/};echo "substr: [${substr}]"
substr=${str##*/};echo "substr: [${substr}]"
# 获得头部字符串,分割符为'/'
headstr=${str%/*};echo "headstr: [${headstr}]"
headstr=${str%%/*};echo "headstr: [${headstr}]"
# 获得指定数量的字符串
numstr=${str:0:8};echo "numstr: [${numstr}]"
numstr=${str:8};echo "numstr: [${numstr}]"
numstr=${str:0-${length}:8};echo "numstr: [${numstr}]"
numstr=${str:0-8};echo "numstr: [${numstr}]"
# 指定字符替换字符串中字符
replstr=${str/https/ftp};echo "replstr: [${replstr}]"
replstr=${str/./-};echo "replstr: [${replstr}]"
replstr=${str//about/index};echo "replstr: [${replstr}]"
# 针对不同的变量状态赋值 (没设定、空值、非空值)
appid=${APP_ID:-NULL}; echo "appid: [${appid}]" # 加有 : 没设定或为空值
appname=${APP_NAME:=null} ;echo "appname: [${appname}]"
appstderr=${APP_STDERR:?null};echo "appstderr: [${appstderr}]"
appadd=${APP_ADD:+null};echo "appadd: [${appadd}]"

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
./demo.sh
string: [https://blog.weiyigeek.top/about/me]
length: [35]
substr: [/blog.weiyigeek.top/about/me]
substr: [me]
headstr: [https://blog.weiyigeek.top/about]
headstr: [https:]
numstr: [https://]
numstr: [blog.weiyigeek.top/about/me]
numstr: [https://]
numstr: [about/me]
replstr: [ftp://blog.weiyigeek.top/about/me]
replstr: [https://blog-weiyigeek.top/about/me]
replstr: [https://blog.weiyigeek.top/index/me]
appid: [NULL]
appname: [null]
./demo.sh: line 26: APP_STDERR: null


0x0n 杂类脚本

示例1.Linux系统信息获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/bin/bash
#zhushi:Linux 系统信息获取
#Author_Name=Weiyi
clear
if [ $# -eq 0 ];then # "$#" 提取位置参数的个数
reset_terminal=$(tput sgr0) #设置高亮输出
#Check OS Type (系统类型)
os=$(uname -o)
echo -e '\E[32m' "OS Type (系统类型):" $reset_terminal $os
#Check OS Release Version and Name (系统发行版本及名字)
os_Rv=$(lsb_release -a | grep "Description" |awk '{print $2 " " $3 " " $4 " "$5$6 }')
echo -e '\E[32m' "OS Release Version and Name (系统发行版本及名字):" $reset_terminal $os_Rv
#Check Architecture (系统Cpu 386 还是 X64架构)
os_Ar=$(uname -m)
echo -e '\E[32m' "Architecture (系统Cpu 386 还是 X64架构):" $reset_terminal $os_Ar
#Check Kernel Release (内核版本)
os_Kr=$(uname -r)
echo -e '\E[32m' "Kernel Release (内核版本)" $reset_terminal $os_Kr
#Check hostname
os_hostname=$(echo $HOSTNAME)
echo -e '\E[32m' "OS Hostname (主机名):" $reset_terminal $os_hostname
#Check Internal IP (内部IP)
os_InIP=$(hostname -I)
echo -e '\E[32m' "Internal IP (内部IP):" $reset_terminal $os_InIP
#Check External IP (外部IP)
os_ExIP=$(curl -s http://ipecho.net/plain)
echo -e '\E[32m' "External IP (外部IP):" $reset_terminal $os_ExIP
#Check DNS
os_Dns=$(cat /etc/resolv.conf |grep -E "\<nameserver[ ]+" |awk '{print $NF}')
# "\<nameserver[ ]+" 表示匹配以nameserver开头的多个[ ]+ //空格
# "$NF" 默认以空格为分割符打印他得最后一行
echo -e '\E[32m' "OS DNS (系统DNS):" $reset_terminal $os_Dns
#Check IF Connected To Internet or not (是否能连接英特网)
ping -c 2 www.baidu.com &>/dev/null && echo "Internet:Connected(正常通信)" || echo "Internet:Disconnected(不能正常通信)"
#Check logged In Users (当前登陆的用户)
who >/tmp/who
echo -e '\E[32m' "Logged In Users (当前登陆的用户)" $reset_terminal && cat /tmp/who
rm -rf /tmp/who
#Check Proc Information
echo -e '\E[35m]' "########### Proc info (内存使用信息) ##############\n"
system_mem_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}END{print (total-free)/1024}' /proc/meminfo)
echo -e '\E[32m' "System Mem Usages (当前系统使用内存信息-MB):" $reset_terminal $system_mem_usages
application_mem_usages=$(awk '/MemTotal/{total=$2}/MemFree/{free=$2}/^Cached/{cached=$2}/Buffers/{buffers=$2}END{print (total-free-cached-buffers)/1024}' /proc/meminfo)
echo -e '\E[32m' "Application Mem Usages (当前应用使用内存信息-MB):" $reset_terminal $application_mem_usages
#Check Cpu Information >> load average后面分别是1分钟、5分钟、15分钟的负载情况
echo -e '\E[35m]' "########### Cpu load info (Cpu负载信息) ##############\n"
load_average=$(top -n 1 -b |grep "load average:" |awk '{print $10 $11 $12}')
echo -e '\E[32m' "Cpu load info (Cpu负载信息):" $reset_terminal $load_average
#Check Disk Information
echo -e '\E[35m]' "########### Disk info (磁盘使用信息) ##############\n"
disk_info=$(df -h |grep -vE "Filesystem|tmpfs" |awk '{printf $1 "\t" $5 "\n"}')
# -p 使用输出更紧凑
echo -e '\E[32m' "Disk Usages (磁盘使用信息):" $reset_terminal $disk_info
fi

WeiyiGeek.

WeiyiGeek.


示例2.进程监控

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
#zhushi:httpd进程restart and if
test=$(ps aux | grep "httpd" | grep -v "grep") #截取Httpd进程,并把结果赋予变量test
if [ -n "$test" ];then
#if test 的值不为空,则执行then中的命令
echo "$(date) httpd is ok!" >> /tmp/autostart-acc.log
echo "httpd服务正常"
else
echo "http服务异常/正在重新启动httpd服务"
/etc/rc.d/init.d/httpd restart &> /dev/null
echo "$(date) restart httpd!!" >> /tmp/autostart-err.log
fi


示例3.apachelog日志分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/bin/bash
#zhushi:Http status number
#author_Name:Weiyi

resettem=$(tput sgr0)
read -t 30 -p "Please,Input access Httpd log pash:" logfile

#Check http status Functions
Check_http_status(){
http_status_codes=$(cat $logfile |grep -ioE 'HTTP\/1\.[0|1]\"[[:blank:]][0-9]{3}' |awk -F "[ ]+" '{
if ( $2>100 && $2<200 )
{i++}
else if ( $2>200 && $2<300 )
{j++}
else if ( $2>300 && $2<400 )
{k++}
else if ( $2>400 && $2<500 )
{n++}
else if ( $2>500 )
{p++}
}END{
print i?i:0,j?j:0,k?k:0,n?n:0,p?p:0,i+j+k+n+p
}')
echo -e '\E[33m' "The Number of http status[100+]:" $resettem ${http_status_codes[0]}
echo -e '\E[33m' "The Number of http status[200+]:" $resettem ${http_status_codes[1]}
echo -e '\E[33m' "The Number of http status[300+]:" $resettem ${http_status_codes[2]}
echo -e '\E[33m' "The Number of http status[400+]:" $resettem ${http_status_codes[3]}
echo -e '\E[33m' "The Number of http status[500+]:" $resettem ${http_status_codes[4]}
echo -e '\E[33m' "All Request numbers:" $resettem ${http_status_codes[5]}
}

#Check http Code 404/403 Functions
Check_http_code()
{
http_code=$(cat $logfile |grep -ioE 'HTTP\/1\.[0|1]\"[[:blank:]][0-9]{3}' |awk -v total=0 -F '[ ]+' '{
if ( $2 != "" )
{code[$2]++;total++}
else
{exit}
}END{
print code[404]?code[404]:0,code[403]?code[403]:0,total
}')
echo -e '\E[33m' "The Number of http status[404]:" $resettem ${http_status_codes[0]}
echo -e '\E[33m' "The Number of http status[403]:" $resettem ${http_status_codes[1]}
echo -e '\E[33m' "All Request numbers:" $resettem ${http_status_codes[2]}
}

#调用函数
Check_http_status
echo -e '\n'
Check_http_code


示例4.Monitor脚本设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
# tput sgr0 终端号关闭
resettem=$(tput sgr0)

declare -A ssharray
i=0
number=""

for script_file in `ls -I "monitor_man.sh" ./`;do
echo -e "\e[1;35m" "The script file:" ${i} '==>' ${resettem} ${script_file}
grep "#zhushi:" ${script_file} # 获取备注信息
ssharray[$i]=${script_file} # 将每个文件传人数组之中
number="${number} | ${i}" # 拼接子符
i=$(( i+1 ))
done

while true
do
read -t 30 -p "Please input a number[ ${number} ]:" file # 输出number变量
if [[ ! ${file} =~ ^[0-9]+ ]];then
exit 0
fi
/bin/sh ./${ssharray[$file]} # 传入数组之中,并执行
done

实例5:日志访问数量统计

1
2
3
4
5
6
7
8
9
# 错误输入到err.txt
result=0
for i in {20..30};
do
count=$(grep -c "/cj/get.do?ksh=" localhost_access_log.2020-11-${i}.txt 2> err.txt)
echo $count
result=$(expr $result + $count)
done
echo $result


示例5.字符串截取之文件拷贝

1
for i in $(cat 1.txt); do src=${i%-*} ; target=${i#*-}; srcname="${src%.*}"; targetname="${target%/*}";mkdir -p ${targetname}; find ${srcname}* -exec cp {} ${target} \; ; done


示例6.按照身份证进行字符串分隔创建目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
#
# $ find gz2020/photo -type f > ks.txt
for id in $(cat ks.txt); do

# 判断路径以及身份证类别
if [[ ${#id} -ne 29 ]]; then
echo ${id} >> exception.txt
else
photo_name="${id##*/}"
id_split="${id:7:2}/${id:9:4}/${id:13:4}"
target_dir="/mnt/f/2020/pz_webchat/${id_split}"
target_file="${target_dir}/${photo_name}"
if [[ ! -e ${target_dir} ]]; then
mkdir -p ${target_dir}
fi

# 区分后缀大小写
ignore_case=$(echo "${target_file}" | grep -c "JPG")
if [[ ${ignore_case} -eq 0 ]];then
if [[ ! -e ${target_file} ]]; then
cp -a ${id} ${target_file} || echo ${id} >> notcopy.txt
else
echo "normal - ${target_file}" >> exsit.txt
fi
else
photo_name_case="${photo_name%.*}.jpg"
target_file_case="${target_dir}/${photo_name_case}"
if [[ ! -e ${target_file_case} ]]; then
cp -a ${id} ${target_file_case} || echo ${id} >> notcopy.txt
else
echo "case - ${target_file} -> ${target_file_case}" >> exsit_case.txt
fi
fi
fi
done


示例7.Jenkins与K8s集群部署脚本实现部署、回退以及覆盖部署
脚本清单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/bin/sh
export K8sMaster="${DEPLOY_USER}@${DEPLOY_HOST}"
export AppName="${APP_FILE##*/}"
export FindAppName=$(find ${WORKSPACE} -maxdepth 2 -type f -name ${AppName})

if [ "${FindAppName}" != "" ]; then
echo "[-Msg]: ${FindAppName} ./${APP_NAME} Copying...."
cp -rf ${FindAppName} ./${APP_NAME}
else
echo "[-Error]: FindAppName param error!"
exit 1
fi

function judge () {
export ExistResult=$(ssh -p ${DEPLOY_PORT} ${K8sMaster} "ls ${APP_DIR} | grep ${RELEASE_VERSION} | wc -l")
}

function deploy () {
if [[ ${ExistResult} -eq 0 || "${RELEASE_VERSION}" == "master" ]];then
scp -P ${DEPLOY_PORT} "${APP_NAME}" ${K8sMaster}:${APP_DIR}${APP_NAME}
else
echo "[-Msg]: /${APP_NAME} current Deploy....."
fi

# 部署脚本
if [[ "${RELEASE_VERSION}" == "master" ]];then
ssh -p ${DEPLOY_PORT} ${K8sMaster} "kubectl -n ${K8S_NAMESPACE} delete pod -l ${K8S_SELECTOR}"
else
ssh -p ${DEPLOY_PORT} ${K8sMaster} "kubectl apply -f ${APP_DIR}${JOB_NAME}.yaml"
fi
}

function rollback () {
if [[ ${ExistResult} -ne 0 ]];then
ssh -p ${DEPLOY_PORT} ${K8sMaster} "kubectl apply -f ${APP_DIR}${JOB_NAME}.yaml"
else
echo "[-Eroor]: /${APP_NAME} version not exsit....."
exit 1
fi
}

function redeploy () {
# 如果是以前部署过则删除以前部署的项目目录,否则重新部署;
if [[ "v${GIT_COMMIT}" = "v${GIT_PREVIOUS_SUCCESSFUL_COMMIT}" || ${ExistResult} -gt 0 ]];then
echo -e "[-Message]: ${RELEASE_VERSION} Version Exsit !"
ssh -p ${DEPLOY_PORT} ${K8sMaster} "find ${APP_DIR} -d -maxdepth 1 -type f -name ${APP_NAME}"
scp -P ${DEPLOY_PORT} "${APP_NAME}" ${K8sMaster}:${APP_DIR}${APP_NAME}
fi

# 重新部署
deploy
}

# 判断是否存在历史版本
judge

case ${PREJECT_OPERATION} in
"deploy")
echo "1.deploy"
deploy
;;
"rollback")
echo "2.rollback"
rollback
;;
"redeploy")
echo "3.redeploy"
redeploy
;;
*)
echo "[-Error] : params.PREJECT_OPERATION Param Error!"
exit 1
;;
esac