LinuxShell
基本语法第一行
第一行必须是 #!/bin/sh。 它不是注释,#!/bin/sh 是对shell的声明,说明你所用的是那种类型的shell及其路径所在 如果没有声明,则脚本将在默认的shell中执行,默认shell是由用户所在的系统定义为执行shell脚本的shell 如果脚本被编写为在Kornshell ksh中运行,而默认运行shell脚本的为C shell csh,则脚本在执行过程中很可能失败 所以建议大家就把 #!/bin/sh 当成C 语言的main函数一样,写shell必须有,以使shell程序更严密 注释
一行开头为 #。 接收参数
脚本文件"copy.sh",其内容如下: m=$1 n=$2 echo $m-$n
执行命令:"sh copy.sh 111 222";输出 111-222 格式化输出日期curdate="`date +%Y%m%d%H%M%S`" echo $curdate
执行结果:20230123105058 exist
退出当前shell脚本,一般来说,返回0表示执行成功,其他值表示没有执行成功。 exist 0 # 返回0 exist 1 # 返回1变量变量命名
shell 变量的命名规则如下:开头是一个字母或下划线,后面可以接任意长度的字母、数字或下划线符号,变量名的字符长度并无限制(Bourne shell中)。不过为了兼容性(一些早期的shell里变量名是有长度限制的),一般还是不要超过255个字符。另外,Linux区分大小写。当用户自己定义变量的时候,要注意变量名不能与 shell 中的关键字重名。 变量赋值
变量名=值
注意:赋值语句两边不能有空格(即 "=" 号两边不能有空格)。等号右边若有空格的话,需要加上引号(单引号或双引号都是可以的)。shell 中可以在变量名前加上 $ 字符来取变量的值。 定义变量
定义单变量: p_name="kang"
使用单变量: echo $p_name".js" # 输出kang.js echo $p_name.js # 输出kang.js cp $p_name.js copy.js;系统变量pwd=$PWD # 当前目录 user=$USER # 当前用户 echo $pwd echo $user
运行脚本后输出: /home/rainman/test rainman数组Shell 并且没有限制数组的大小,理论上可以存放无限量的数据 Shell 数组元素的下标也是从 0 开始计数 获取数组中的元素要使用下标[ ],下标可以是一个整数,也可以是一个结果为整数的表达式、 下标必须大于等于 0 常用的 Bash Shell 只支持一维数组,不支持多维数组 #!/bin/bash nums=(29 100 13 8 91 44) echo ${nums[@]} # 输出所有数组元素 nums[10]=66 # 给第10个元素赋值(此时会增加数组长度) echo ${nums[*]} # 输出所有数组元素 echo ${nums[4]} # 输出第4个元素获取数组长度
利用@或*,可以将数组扩展成列表,然后使用#来获取数组元素的个数,格式如下: ${#array_name[@]} ${#array_name[*]}
其中 array_name 表示数组名。两种形式是等价的,选择其一即可。示例如下: #!/bin/bash nums=(29 100 13) echo ${#nums[*]} # 输出3 # 向数组中添加元素 nums[10]="http://c.biancheng.net/shell/" echo ${#nums[@]} # 输出4数组拼接
拼接数组的思路是:先利用@或*,将数组扩展成列表,然后再合并到一起。具体格式如下: array_new=(${array1[@]} ${array2[@]}) array_new=(${array1[*]} ${array2[*]})
两种方式是等价的,选择其一即可。其中,array1 和 array2 是需要拼接的数组,array_new 是拼接后形成的新数组。完整示例如下: #!/bin/bash array1=(23 56) array2=(99 "https://www.baidu.com/") array_new=(${array1[@]} ${array2[*]}) echo ${array_new[@]} # 也可以写作 ${array_new[*]}
运行结果:23 56 99 https://www.baidu.com/ 删除数组元素
在 Shell 中,使用 unset 关键字来删除数组元素,具体格式如下: unset array_name[index]
其中,array_name 表示数组名,index 表示数组下标。如果不写下标,而是写成下面的形式: unset array_name
那么就是删除整个数组,所有元素都会消失。 #!/bin/bash arr=(23 56 99 "https://www.baidu.com/") unset arr[1] echo ${arr[@]} unset arr echo ${arr[*]}
运行结果:23 99 https://www.baidu.com/ 算术运算expr命令求值
使用 expr 命令对算术表达式求值,常见的命令如下:
表达式
说明
expr1 | expr2
若 expr1 非零,则等于 expr1 ,否则等于 expr2。
expr1 & expr2
只要有一个表达式为零,则等于零,否则等于 expr1。
expr1 = expr2
等于(与 == 是同义的),若两式相等则结果为1,不等结果为0
expr1 > expr2
大于
expr1 >= expr2
大于等于
expr1 < expr2
小于
expr1 <= expr2
小于等于
expr1 != expr2
不等于
expr1 + expr2
加
expr1 - expr2
减
expr1 * expr2
乘
expr1 / expr2
整除
expr1 % expr2
取余
注意:在 expr 命令所支持的操作符中,"|、&、<、<=、>、>=、 * " 这几个需要用 符进行转义再使用。此外,表达式的各字符之间需要用空格隔开。使用方法如下: #!/bin/bash a=5;b=6;c=0 echo $(expr $a | $c) # 输出 5 echo $(expr $b & $c) # 输出 0 echo $(expr $a & $b) # 输出 5 echo $(expr $a <= $b) # 输出 1 echo $(expr $a * $b) # 输出 30 echo $(expr $a = 2) # 输出 1 exit 0
逻辑符号 命令1 && 命令2:如果左边的"命令1"执行成功,那么右边的"命令2"才会被执行 命令1 || 命令2:与&&相反。如果"命令1"未执行成功,那么就执行"命令2" $(( ... ))求值
使用 $(( ... )) 的方式对算术表达式求值。
expr 虽然功能强大,但是上面已经提到,在进行一些运算的时候,需要使用 符来进行转义,这对于阅读代码的人来说并不友好。另一方面,expr 命令执行起来其实很慢,因为它需要调用一个新的 shell 来处理 expr 命令。更新更好的一种做法是使用 $((...)) 扩展的方式。只需要将准备求值的表达式放在 $((...)) 的括号中即可进行简单的算术求值。且,所有支持 $$(( ... )) 的 shell,都可以让用户在提供变量名称时,无须前置 $$$$(( ... )) 的 shell,都可以让用户在提供变量名称时,无须前置 $$$ 符。用一段代码演示一下用法: #!/bin/bash a=5;b=6 echo $(($a + $b)) # 输出 11 。在变量名前加上 $,这在shell中一般是取变量值的意思 echo $((a + b)) # 输出 11 。可见,变量前不加 $ 也是可以的,为了简便,后面的代码就不加 $ 了 echo $((a | b)) # 输出 7 。这里的 | 是按位或操作符 echo $((a || b)) # 输出 1 。这里的 || 是逻辑或操作符 echo $((a & b)) # 输出 4 。这里的 & 是按位与操作符 echo $((a && b)) # 输出 1 。这里的 && 是逻辑与操作符 echo $((a * b)) # 输出 30 echo $((a == b)) # 输出 0 exit 0字符串
字符串可以由单引号" "包围,也可以由双引号" "包围,也可以不用引号。它们之间的区别: 由单引号" "包围的字符串任何字符都会原样输出,在其中使用变量是无效的字符串中不能出现单引号,即使对单引号进行转义也不行 由双引号" "包围的字符串如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出字符串中可以出现双引号,只要它被转义了就行 不被引号包围的字符串不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析 拼接
字符串拼接连接、合并。 #!/bin/bash name="Shell" url="https://www.baidu.com/" str1=$name$url # 中间不能有空格 str2="$name $url" # 如果被双引号包围,那么中间可以有空格 str3=$name": "$url # 中间可以出现别的字符串 str4="$name: $url" # 这样写也可以 str5="${name}Script: ${url}index.html" # 这个时候需要给变量名加上大括号 echo $str1 echo $str2 echo $str3 echo $str4 echo $str5截取
格式
说明
${string: start :length}
从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。
${string: start}
从 string 字符串的左边第 start 个字符开始截取,直到最后。
${string: 0-start :length}
从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。
${string: 0-start}
从 string 字符串的右边第 start 个字符开始截取,直到最后。
${string#*chars}
从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string##*chars}
从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。
${string%*chars}
从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。
${string%%*chars}
从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。 条件判断
test 命令可以处理 shell 脚本中的各类工作。它产生的不是一般的输出,而是可使用的退出状态。test 命令通过接受各种不同的参数,来控制要执行哪种测试。在许多系统上,test 命令与 [ 命令的作用其实是一样的,使用 [ 命令的时候,一般在结尾加上 ] 符号,使代码更具可读性。另外,需要注意一点的是,在使用 [ 命令时,[ 符号与被检查的语句之间应该留有空格 。 shell 中通常使用 test 命令来产生控制结构所需要的条件,根据 test 命令的退出码决定是否需要执行后面的代码。
test 命令可以使用的条件类型有三类:字符串比较、算术比较和与文件有关的条件测试。 字符串比较
表达式
结果
string1 = string2
如果两个字符串相同则结果为真
string1 != string2
如果两个字符串不同则结果为真
-n string
如果字符串不为空则结果为真
-z string
如果字符串为空(null),则结果为真
使用方法如下: str1="tongye" str2="ttyezi" # 用 test 命令,test 语句的结果将作为 if 的判断条件,结果为真即条件为真,则执行 if 下面的语句 if test "$str1" = "$str2" ; then .... fi # 用 [ 命令的话,可以这样,注意 [ 与表达式之间要有空格 if [ "$str1" != "$str2" ] ; then .... fi if [ -n "$str1" ] ; then ....fi
使用字符串比较的时候,必须给变量加上引号 " " ,避免因为空字符或字符串中的空格导致一些问题。实际上,对于条件测试语句里的变量,都建议加上双引号,能做字符串比较的时候,不要用数值比较。 算术比较
算术比较
结果
expr1 -eq expr2
如果两个表达式相等,则结果为真
expr1 -ne expr2
如果两个表达式不相等,则结果为真
expr1 -gt expr2
如果 expr1 > expr2 ,则结果为真
expr1 -ge expr2
如果 expr1 >= expr2 ,则结果为真
expr1 -lt expr2
如果 expr1 < expr2,则结果为真
expr1 -le expr2
如果 expr1 <= expr2,则结果为真
!expr
如果表达式为假,则结果为真
使用方法如下: num1=2 num2=3 if [ "$num1" -eq "$num2" ] ; then ... fi if [ "$num1" -le "$num2" ] ; then .... fi
注意算术比较和字符串比较之间的不同之处,字符串比较比较的是两个字符串,数字也是能组成字符串的,因此,当我们使用字符串比较的方式和数字比较的方式来比较两串数字的时候,结果会有些不同。案例如下: #!/bin/bash val1="1" val2="001" val3="1 " # 字符串 val3 在 1 的后面还有一个空格 [ "$val1" = "$val2" ] echo $? # 使用字符串比较,退出码为 1,说明两个字符串不相等 [ "$val1" -eq "$val2" ] echo $? # 使用数值比较,退出码为 0,说明两个数值相等 [ "$val1" = "$val3" ] echo $? # 退出码为 1 [ "$val1" -eq "$val3" ] echo $? # 退出码为 0 exit 0
需要注意的是,如果在编写代码时,变量没有加上双引号,上述程序的结果又会不同,仅对 val3 进行取值,将会忽略该字符串中的空格,则第三个表达式的退出码将为 0 。这也说明了在变量两边加上双引号的重要性。 文件条件测试
文件条件测试
结果
-d file
如果文件是一个目录,则结果为真
-e file
如果文件存在,则结果为真。注意,历史上 -e 选项不可移植,所以通常使用的是 -f 选项
-f file
如果文件存在且为普通文件,则结果为真
-g file
如果文件的 set-group-id 位被设置,则结果为真
-r file
如果文件可读,则结果为真
-s file
如果文件大小不为 0 ,则结果为真
-u file
如果文件的 set-user-id 为被设置,则结果为真
-w file
如果文件可写,则结果为真
-x file
如果文件可执行,则结果为真
用一个例子演示一下: #!/bin/bash if [ -f /bin/bash ] ; then echo "file /bin/bash exists" fi if [ -d /bin/bash ] ; then echo "/bin/bash is a directory" else echo "/bin/bash is not a directory" fiexit 0流程控制if语句
"["和"]"前后的空格必须有,否则提示错误。 m="kang2" if [ "$m" == "kang" ]; then echo "kang" elif [ $m == "kang2" ]; then echo "kang2" else echo "no" fi
示例:判断文件夹 if [ -d "./js" ]; then echo "js是文件夹" ficase语句
与其他编程语言中的 case 语句类似, shell 中的 case 语句也可以用来进行模式匹配,语法如下: case variable in pattern [ | pattern ] ... ) statements;; pattern [ | pattern ] ... ) statements;; ... esac
关于 case 的语法,有以下几点需要说明一下: case 语句以 case 作为开头,以 esac 作为结尾 case 语句的每个模式行都是以双分号 ;; 结尾的 一个模式行可以合并匹配多个模式,使用 | 符作为分隔 一个模式行可以执行多条语句,各语句之间可以使用单分号 ; 隔开,这也是为什么每行的结尾要使用双分号 ;; 作为结束标志的原因 case 语句支持使用正则表达式作为匹配项,这使得 case 语句的功能更为强大 #!/bin/bash read -p "please keyin a word:" -t 5 word case $word in [a-z] | [A-Z] ) echo "You have keyin a letter";; [1-9] ) echo "You have keyin a number";; * ) echo "Unknow input" esac exit 0
这段代码从键盘输入一个字符,然后进行匹配,判断这个字符是字母还是数字,都不是的话返回未知输入。 for语句
循环:for/do/done。注意循环项是以"空格"拆分的字符串。
foreach形式: name="rain man"s blog" for loop in $name; do echo $loop; done
自定义步长循环: for ((初始值; 限定值; 执行步长 )) do # 程序段 done # 例如 for (( i = 1; i < ${number}; i = i + 1 )) do # 程序段 done #!/bin/bash for name in tongye wuhen xiaodong wufei laowang do echo $name done exit 0 # 依次输出:tongye wuhen xiaodong wufei laowangwhile与until语句
如果你需要进行循环操作而是先不知道需要循环的次数,可以使用 while 循环,while 循环的语法如下: while condition do statements done
until 循环语句的功能与 while 一样,不同的是对于条件判断结果的处理上。until 循环的语法如下: until condition do statements done
在 while 和 until 语句中,condition 是判断条件,不同的是,while 语句中,若判断条件为真,则执行循环体;until 语句中,若判断条件为真,则停止执行循环体。 #!/bin/bash i=1 while [ "$i" -le 10 ] do read -p "please keyin a number:" i done 9 10 echo "$i" 11 12 exit 0
这段代码从键盘中输入一个数字,直到输入数值大于 10,退出循环并打印最后输入的那个值。 高级命令输出重定向标准输出重定向command >file:以覆盖的方式,把 command 的正确输出结果输出到 file 文件中command >>file:以追加的方式,把 command 的正确输出结果输出到 file 文件中 标准错误输出重定向command 2>file:以覆盖的方式,把 command 的错误信息输出到 file 文件中command 2>>file:以追加的方式,把 command 的错误信息输出到 file 文件中 正确输出和错误信息同时保存command >file 2>&1:以覆盖的方式,把正确输出和错误信息同时保存到同一个文件(file)中command >>file 2>&1:以追加的方式,把正确输出和错误信息同时保存到同一个文件(file)中command >file1 2>file2:以覆盖的方式,把正确输出结果输出到 file1 文件中,把错误信息输出到 file2 文件中command >>file1 2>>file2: 以追加的方式,把正确输出结果输出到 file1 文件中,把错误信息输出到 file2 文件中
示例: #!/bin/bash for str in "test1" "test2" "test3" do echo $str >>demo.txt # 将输入结果以追加的方式重定向到文件 done[localhost]$ ls -l >demo.txt # 重定向 [localhost]$ cat demo.txt # 查看文件内容自定义函数
$? 获取函数的返回值。 #!/bin/bash # 得到两个数相加的和 function add(){ return `expr $1 + $2` } add 23 50 # 调用函数 echo $? # 获取函数返回值常用脚本
检测两台服务器指定目录下的文件一致性 #!/bin/bash ##################################### #检测两台服务器指定目录下的文件一致性 ##################################### #通过对比两台服务器上文件的md5值,达到检测一致性的目的 dir=/data/web b_ip=192.168.88.10 #将指定目录下的文件全部遍历出来并作为md5sum命令的参数,进而得到所有文件的md5值,并写入到指定文件中 find $dir -type f|xargs md5sum > /tmp/md5_a.txt ssh $b_ip "find $dir -type f|xargs md5sum > /tmp/md5_b.txt" scp $b_ip:/tmp/md5_b.txt /tmp #将文件名作为遍历对象进行一一比对 for f in `awk "{print 2} /tmp/md5_a.txt"` do #以a机器为标准,当b机器不存在遍历对象中的文件时直接输出不存在的结果 if grep -qw "$f" /tmp/md5_b.txt then md5_a=`grep -w "$f" /tmp/md5_a.txt|awk "{print 1}"` md5_b=`grep -w "$f" /tmp/md5_b.txt|awk "{print 1}"` #当文件存在时,如果md5值不一致则输出文件改变的结果 if [ $md5_a != $md5_b ] then echo "$f changed." fi else echo "$f deleted." fi done
定时清空文件内容,定时记录文件大小 #!/bin/bash ################################################################ #每小时执行一次脚本(任务计划),当时间为0点或12点时,将目标目录下的所有文件内 #容清空,但不删除文件,其他时间则只统计各个文件的大小,一个文件一行,输出到以时#间和日期命名的文件中,需要考虑目标目录下二级、三级等子目录的文件 ################################################################ logfile=/tmp/`date +%H-%F`.log n=`date +%H` if [ $n -eq 00 ] || [ $n -eq 12 ] then #通过for循环,以find命令作为遍历条件,将目标目录下的所有文件进行遍历并做相应操作 for i in `find /data/log/ -type f` do true > $i done else for i in `find /data/log/ -type f` do du -sh $i >> $logfile done fi
检测网卡流量,并按规定格式记录在日志中 #!/bin/bash ####################################################### #检测网卡流量,并按规定格式记录在日志中 #规定一分钟记录一次 #日志格式如下所示: #2019-08-12 20:40 #ens33 input: 1234bps #ens33 output: 1235bps ######################################################3 while : do #设置语言为英文,保障输出结果是英文,否则会出现bug LANG=en logfile=/tmp/`date +%d`.log #将下面执行的命令结果输出重定向到logfile日志中 exec >> $logfile date +"%F %H:%M" #sar命令统计的流量单位为kb/s,日志格式为bps,因此要*1000*8 sar -n DEV 1 59|grep Average|grep ens33|awk "{print $2," ","input:"," ",$5*1000*8,"bps"," ",$2," ","output:"," ",$6*1000*8,"bps"}" echo "####################" #因为执行sar命令需要59秒,因此不需要sleep done
杀死所有脚本 #!/bin/bash ################################################################ #有一些脚本加入到了cron之中,存在脚本尚未运行完毕又有新任务需要执行的情况, #导致系统负载升高,因此可通过编写脚本,筛选出影响负载的进程一次性全部杀死。 ################################################################ ps aux|grep 指定进程名|grep -v grep|awk "{print $2}"|xargs kill -9
从FTP服务器下载文件 #!/bin/bash if [ $# -ne 1 ]; then echo "Usage: $0 filename" fi dir=$(dirname $1) file=$(basename $1) ftp -n -v << EOF # -n 自动登录 open 192.168.1.10 # ftp服务器 user admin password binary # 设置ftp传输模式为二进制,避免MD5值不同或.tar.gz压缩包格式错误 cd $dir get "$file" EOF
监测Nginx访问日志502情况,并做相应动作
假设服务器环境为lnmp,近期访问经常出现502现象,且502错误在重启php-fpm服务后消失,因此需要编写监控脚本,一旦出现502,则自动重启php-fpm服务。 #场景: #1.访问日志文件的路径:/data/log/access.log #2.脚本死循环,每10秒检测一次,10秒的日志条数为300条,出现502的比例不低于10%(30条)则需要重启php-fpm服务 #3.重启命令为:/etc/init.d/php-fpm restart #!/bin/bash ########################################################### #监测Nginx访问日志502情况,并做相应动作 ########################################################### log=/data/log/access.log N=30 #设定阈值 while : do #查看访问日志的最新300条,并统计502的次数 err=`tail -n 300 $log |grep -c "502" "` if [ $err -ge $N ] then /etc/init.d/php-fpm restart 2> /dev/null #设定60s延迟防止脚本bug导致无限重启php-fpm服务 sleep 60 fi sleep 10 done
批量修改文件名 # touch article_{1..3}.html # ls article_1.html article_2.html article_3.html # 目的:把article改为bbs # 方法1 for file in $(ls *html); do mv $file bbs_${file#*_} # mv $file $(echo $file |sed -r "s/.*(_.*)/bbs1/") # mv $file $(echo $file |echo bbs_$(cut -d_ -f2) done # 方法2 for file in $(find . -maxdepth 1 -name "*html"); do mv $file bbs_${file#*_} done # 方法3 rename article bbs *.html
统计当前目录中以.html结尾的文件总大 # 方法1 find . -name "*.html" -exec du -k {} ; |awk "{sum+=$1}END{print sum}" # 方法2 for size in $(ls -l *.html |awk "{print $5}"); do sum=$(($sum+$size)) done echo $sum
扫描主机端口状态 #!/bin/bash HOST=$1 PORT="22 25 80 8080" for PORT in $PORT; do if echo &>/dev/null > /dev/tcp/$HOST/$PORT; then echo "$PORT open" else echo "$PORT close" fi done
输入数字运行相应命令 #!/bin/bash ############################################################## #输入数字运行相应命令 ############################################################## echo "*cmd menu* 1-date 2-ls 3-who 4-pwd 0-exit " while : do #捕获用户键入值 read -p "please input number :" n n1=`echo $n|sed s"/[0-9]//"g` #空输入检测 if [ -z "$n" ] then continue fi #非数字输入检测 if [ -n "$n1" ] then exit 0 fi break done case $n in 1) date ;; 2) ls ;; 3) who ;; 4) pwd ;; 0) break ;; #输入数字非1-4的提示 *) echo "please input number is [1-4]" esac
Expect实现SSH免交互执行命令
Expect是一个自动交互式应用程序的工具,如telnet,ftp,passwd等。需先安装expect软件包。 # 将expect脚本独立出来为登录脚本 # cat login.exp #!/usr/bin/expect set ip [lindex $argv 0] set user [lindex $argv 1] set passwd [lindex $argv 2] set cmd [lindex $argv 3] if { $argc != 4 } { puts "Usage: expect login.exp ip user passwd" exit 1 } set timeout 30 spawn ssh $user@$ip expect { "(yes/no)" {send "yesr"; exp_continue} "password:" {send "$passwdr"} } expect "$user@*" {send "$cmdr"} expect "$user@*" {send "exitr"} expect eof # 执行命令脚本:写个循环可以批量操作多台服务器 #!/bin/bash HOST_INFO=user_info.txt for ip in $(awk "{print $1}" $HOST_INFO) do user=$(awk -v I="$ip" "I==$1{print $2}" $HOST_INFO) pass=$(awk -v I="$ip" "I==$1{print $3}" $HOST_INFO) expect login.exp $ip $user $pass $1 done # Linux主机SSH连接信息: # cat user_info.txt 192.168.1.120 root 123456
监控httpd的进程数,根据监控情况做相应处理 #!/bin/bash ############################################################################################################################### #需求: #1.每隔10s监控httpd的进程数,若进程数大于等于500,则自动重启Apache服务,并检测服务是否重启成功 #2.若未成功则需要再次启动,若重启5次依旧没有成功,则向管理员发送告警邮件,并退出检测 #3.如果启动成功,则等待1分钟后再次检测httpd进程数,若进程数正常,则恢复正常检测(10s一次),否则放弃重启并向管理员发送告警邮件,并退出检测 ############################################################################################################################### #计数器函数 check_service() { j=0 for i in `seq 1 5` do #重启Apache的命令 /usr/local/apache2/bin/apachectl restart 2> /var/log/httpderr.log #判断服务是否重启成功 if [ $? -eq 0 ] then break else j=$[$j+1] fi #判断服务是否已尝试重启5次 if [ $j -eq 5 ] then mail.py exit fi done } while : do n=`pgrep -l httpd|wc -l` #判断httpd服务进程数是否超过500 if [ $n -gt 500 ] then /usr/local/apache2/bin/apachectl restart if [ $? -ne 0 ] then check_service else sleep 60 n2=`pgrep -l httpd|wc -l` #判断重启后是否依旧超过500 if [ $n2 -gt 500 ] then mail.py exit fi fi fi #每隔10s检测一次 sleep 10 done
iptables自动屏蔽访问网站频繁的IP #场景:恶意访问,安全防范 #1)屏蔽每分钟访问超过200的IP #方法1:根据访问日志(Nginx为例) #!/bin/bash DATE=$(date +%d/%b/%Y:%H:%M) ABNORMAL_IP=$(tail -n5000 access.log |grep $DATE |awk "{a[$1]++}END{for(i in a)if(a[i]>100)print i}") #先tail防止文件过大,读取慢,数字可调整每分钟最大的访问量。awk不能直接过滤日志,因为包含特殊字符。 for IP in $ABNORMAL_IP; do if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then iptables -I INPUT -s $IP -j DROP fi done #方法2:通过TCP建立的连接 #!/bin/bash ABNORMAL_IP=$(netstat -an |awk "$4~/:80$/ && $6~/ESTABLISHED/{gsub(/:[0-9]+/,"",$5);{a[$5]++}}END{for(i in a)if(a[i]>100)print i}") #gsub是将第五列(客户端IP)的冒号和端口去掉 for IP in $ABNORMAL_IP; do if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then iptables -I INPUT -s $IP -j DROP fi done #2)屏蔽每分钟SSH尝试登录超过10次的IP #方法1:通过lastb获取登录状态: #!/bin/bash DATE=$(date +"%a %b %e %H:%M") #星期月天时分 %e单数字时显示7,而%d显示07 ABNORMAL_IP=$(lastb |grep "$DATE" |awk "{a[$3]++}END{for(i in a)if(a[i]>10)print i}") for IP in $ABNORMAL_IP; do if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then iptables -I INPUT -s $IP -j DROP fi done #方法2:通过日志获取登录状态 #!/bin/bash DATE=$(date +"%b %d %H") ABNORMAL_IP="$(tail -n10000 /var/log/auth.log |grep "$DATE" |awk "/Failed/{a[$(NF-3)]++}END{for(i in a)if(a[i]>5)print i}")" for IP in $ABNORMAL_IP; do if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then iptables -A INPUT -s $IP -j DROP echo "$(date +"%F %T") - iptables -A INPUT -s $IP -j DROP" >>~/ssh-login-limit.log fi done
根据web访问日志,封禁请求量异常的IP,如IP在半小时后恢复正常,则解除封禁 #!/bin/bash #################################################################################### #根据web访问日志,封禁请求量异常的IP,如IP在半小时后恢复正常,则解除封禁 #################################################################################### logfile=/data/log/access.log #显示一分钟前的小时和分钟 d1=`date -d "-1 minute" +%H%M` d2=`date +%M` ipt=/sbin/iptables ips=/tmp/ips.txt block() { #将一分钟前的日志全部过滤出来并提取IP以及统计访问次数 grep "$d1:" $logfile|awk "{print $1}"|sort -n|uniq -c|sort -n > $ips #利用for循环将次数超过100的IP依次遍历出来并予以封禁 for i in `awk "$1>100 {print $2}" $ips` do $ipt -I INPUT -p tcp --dport 80 -s $i -j REJECT echo "`date +%F-%T` $i" >> /tmp/badip.log done } unblock() { #将封禁后所产生的pkts数量小于10的IP依次遍历予以解封 for a in `$ipt -nvL INPUT --line-numbers |grep "0.0.0.0/0"|awk "$2<10 {print $1}"|sort -nr` do $ipt -D INPUT $a done $ipt -Z } #当时间在00分以及30分时执行解封函数 if [ $d2 -eq "00" ] || [ $d2 -eq "30" ] then #要先解再封,因为刚刚封禁时产生的pkts数量很少 unblock block else block fi
添加脚本开机自启动 # 将脚本移动到/etc/rc.d/init.d目录 mv test.sh /etc/rc.d/init.d/test.sh # 赋予可执行权限 chmod +x /etc/rc.d/init.d/test.sh # 添加脚本到开机自动启动项目中 cd /etc/rc.d/init.d chkconfig --add test.sh chkconfig test.sh on
冬季当养肾,两味中药泡水,滋阴助阳,延年不老一阵东风一阵寒,冬天来了,有人欢喜,有人愁!用好两味中药,调理阴阳,皆大欢喜!对于阳虚体质之人,怕冷伴随整个冬季,四肢冰冷,手脚冰凉,夜尿多,腰膝冷痛实在令人忧愁。对于阴虚体质之人
阴囊潮湿不等于阴囊湿热,也会有寒湿下注导语阴囊潮湿不等于阴囊湿热,也会有寒湿下注最近不少阴囊潮湿的朋友总是问我为什么阴囊潮湿总是好不了,有时候清热就会拉肚子便溏?阴囊潮湿对于很多男性朋友都有过。只不过很多人即使有消失得
被男朋友打屁股时,为啥会产生一种满足感?原来有生理变化参考资料1CaraStreitetal。Negativeemotionalityanddisciplineaslongtermpredictorsofbehavioraloutco
虔草冬虫夏草怎么吃才有效果,有什么需要注意的?正宗野生冬虫夏草含有虫草酸虫草多肽虫草多糖等多种营养物质,以及人体需要的微量元素和蛋白质,可以补充人体所需的全面营养,是滋补佳品。对于刚开始吃虫草的朋友,小编推荐的就是虫草泡茶。虫
香菜不能吃?关于吃香菜的谣言芫荽,你可能没听过,但是说到它的别名你肯定知道香菜。香菜是人们熟悉的提味蔬菜,状似芹,叶小且嫩,茎纤细,味郁香,是汤饮中的佐料,多用于做凉拌菜佐料,或烫料面类菜中提味用。喜欢香菜和
嚼槟榔,能养生?我国居民中因嚼食槟榔而产生口腔病变的人数近年来呈快速增长之势。为强化槟榔制品监管,防范食品安全风险,江西南昌浙江义乌四川自贡等多地出台监管措施,要求槟榔制品不得作为食品销售。然而,
你吃过超市里的冻鸡腿吗?为啥这么便宜现在经济形式不好许多人手头紧,但生活还得继续,肉得吃猪肉牛肉贵那就选鸡肉吧,论鸡哪肉最多那肯定是鸡腿了,话说回来现在鸡腿可是真便宜啊,基本一斤不到十块钱,有的地方五块钱一斤,都说便
食补吃出好容颜初冬季节,天气一天比一天寒冷,在这种情况下,就要及时补充身体所需的营养成分,冬天一定要多吃猪肝鸡蛋,能够增强身体免疫力,补充气血,让身体更加强健,而且也能吃出好容颜。豆腐鸡蛋羹原料
教你4款早餐饼的做法,5分钟出锅,鲜香又美味,上桌孩子都喜欢吃一年之计在于春,一天之计在于晨,一日三餐中,尤其早餐这一顿尤为重要,大脑经过了一夜的休整,急需营养补充,如果忽略了吃早餐,那么势必会影响上午的工作和学习,造成记忆力减退,注意力不集
最适合下饭的4道家常菜,鲜香美味,营养丰富,学会了做给家人吃作为上班族来说,下班之后,真恨不得好好休息一下,晚饭更是不想下厨,劳累了不说,最主要的是不知如何下手,外面的饭菜虽然好吃,但避免不了科技和狠活,长久反复下去,经济实力也支撑不住,今
西红柿超好吃的做法,味道鲜美,10分钟就搞定,我家经常吃西红柿超好吃的做法,味道鲜美,10分钟就搞定,我家经常吃。西红柿,又叫番茄,可以说是生活中普通再普通的一种食物,生活中常见的有红色,青色,黄色等,可以熟吃也可以生吃。也可以加工成酱
隐私数据被泄露,危险离你我还有多远互联网时代,我们每个人无可避免都要接触网络,当我们享受着互联网带来的便利,个人信息被过度提取时,危险也在悄然来临。一个相机软件,必须提取通讯录才能用吗?一个音乐播放器,必须开启定位
卧龙苍天陨落黄天凶妖寨旗帜位置图大全,黄天凶妖寨牙旗在哪?卧龙苍天陨落黄天凶妖寨旗帜是游戏中可交互的建筑,玩家们插旗子后可以提升不屈等级,很多玩家想知道第二节23地图中这些旗子在哪解锁,那么本文就为大家带来卧龙苍天陨落黄天凶妖寨旗帜位置介
浓眉轰3986被迫攻防组一把抓哈姆四后卫累瘫他詹皇心酸转移头条创作挑战赛北京时间3月6日,湖人113105拒绝勇士逆转。这场比赛湖人上半场一度领先20分,但半场打完勇士缩小到2分,第三节湖人顶住了勇士的攻势再度拉开到7分,末节戴维斯带着四
新余有哪些富豪?宜春人成江西首富,2人在广东发家,财富超10亿文龙溪来源商业传奇2021年胡润百富榜发布,江西闯出一匹黑马,李良彬取代了上一年来自抚州的正邦林印孙,成为新的江西首富,财富达545亿元,增长263。说是黑马,其实并不意外,之前两
杉杉股份90后少帅郑驹进入董事会接掌500亿商业巨头曾称不会盲目扩张长江商报消息长江商报记者刘方益没有意外,杉杉系进入交棒程序,传奇甬商郑永刚的未竟事业将交给儿子郑驹。3月2日,杉杉股份(600884。SH)公告,董事会提名郑驹为公司第十届董事会非
犹太智慧从诅咒到祝福爱能掩盖一切罪(箴1012)从诅咒到祝福雅各阿,你的帐棚何其美你的住处何其美。MatovuohalechaYaakovmishkenotechaYisrael。读一下希伯来语,对于
邪门歪道的光明就在今日文宋冬野我实在不想从进入成人世界后的喜当爹之类扭曲的事说起,更何况我一直强求着自己不要再没事闲的强说愁,尽管漫长的青春期先生遗留在我脑子里的祸根已经让我比别人家的孩子偏激了太多。我
人是什么,为什么有烦恼,当你读懂了这篇文章就知道了人出生之后对所有的事情都是未知的,都要去学,去了解他的特征。知道事情的过去和以后,才知道事情的有可为和不可为,去认识身边所有人,找到和自己适配的人一起去探索。当自己力量不够的时候要
接纳并享受孤独,是最自洽的生活状态著名作家周国平曾说人这一生注定是一场孤独的修行。无聊者自厌,寂寞者自怜,孤独者自足。孤独似乎成了我们生活的常态,很多人总想着逃离。但越逃避,孤独感就越强。然而,也有人默默承受着孤独
人都有阳光与黑暗面曾记得一则小故事有个叫钱乐的人,经常对自己哪都不满意。小时候,他觉得自己是世界上最讨人厌最不懂得交朋友最不受欢迎的孩子。长大后,他则觉得自己是世界上最没有魅力最无能最孤独的男人。为
杰伦格林下赛季需要锁定一致的目标至少要努力多赢比赛直播吧3月6日讯火箭今日142110大胜马刺,赛后,火箭后卫杰伦格林接受了媒体采访。杰伦格林认为火箭上下在下赛季必须锁定相同的目标关于下个赛季,我们都要达成共识。我们知道以我们的战