实用shell脚本学习分享一

1、生成指定日期文件log

请按照这样的日期格式(xxxx-xx-xx)每日生成一个文件,例如生成的文件名为2020-12-20.log, 并且把磁盘的使用情况写到到这个文件中,不用考虑cron,仅仅写脚本即可

bash 复制代码
本题答案:

```
#! /bin/bash
d=`date +%F`
logfile=$d.log
df -h > $logfile
```

需求升级:
```
#!/bin/bash
d=`date +%F`
dir=/data/logs/disklog
if [ ! -d $dir ]
then
    mkdir -p $dir
fi
df -h > $dir/$d.log
find $dir/ -mtime +365 |xargs rm

```
2、统计出每个IP访问量有多少

题目要求

有日志1.log,部分内容如下

```

112.111.12.248 -- 25/Sep/2013:16:08:31 +0800formula-x.haotui.com "/seccode.php?update=0.5593110133088248″ 200″http://formula-x.haotui.com/registerbbs.php" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)"

61.147.76.51 -- 25/Sep/2013:16:08:31 +0800xyzdiy.5d6d.com "/attachment.php?aid=4554&k=9ce51e2c376bc861603c7689d97c04a1&t=1334564048&fid=9&sid=zgohwYoLZq2qPW233ZIRsJiUeu22XqE8f49jY9mouRSoE71″ 301″http://xyzdiy.5d6d.com/thread-1435-1-23.html" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"

```

统计出每个IP访问量有多少

bash 复制代码
#### 核心要点
awk、sort、uniq命令

#### 参考答案
```
awk '{print $1}' 1.log|sort |uniq -c |sort -n -r
```
3、计算一下linux系统所有进程占用内存大小的和。
bash 复制代码
#!/bin/bash
sum=0
for n in `ps aux |grep -v 'TIME COMMAND'|awk '{print $6}'`
do
    sum=$[$sum+$n]
done
echo $sum
4、 设计一个脚本,监控远程的一台机器(假设ip为180.163.26.39)的存活状态,当发现宕机时发一封邮件给你自己。

核心要点

ping -c10 180.163.26.39 通过ping来判定对方是否在线

发邮件脚本 https://aminglinux.coding.net/public/aminglinux-book/aminglinux-book/git/files/master/D22Z/mail2.py

bash 复制代码
#!/bin/bash
n=`ping -c5 180.163.26.39|grep 'packet' |awk -F '%' '{print $1}' |awk '{print $NF}'`
if [ -z "$n" ]
then
    echo "脚本有问题。"
    python mail.py  $m "检测机器存活脚本$0有问题" "获取变量的值为空"
    exit
else
    n1=`echo $n|sed 's/[0-9]//g'`
    if [ -n "$n" ]
    then
        echo "脚本有问题。"
        python mail.py  $m "检测机器存活脚本$0有问题" "获取变量的值不是纯数字"
        exit 
    fi
fi

if 
m=123@qq.com
while :
do
    if [ $n -ge 50 ]
    then
    	python mail.py $m "机器宕机" "丢包率是$n%"
    fi
    sleep 30
done
5、找到/123目录下所有后缀名为.txt的文件
  1. 批量修改.txt为.txt.bak

  2. 把所有.bak文件打包压缩为123.tar.gz

  3. 批量还原文件的名字,即把增加的.bak再删除

核心要点

* find用来查找所有.txt文件

* tar打包一堆文件

* 还原文件名用for循环

bash 复制代码
#!/bin/bash
find /123/ -type f -name "*.txt" > /tmp/txt.list 
for f in `cat /tmp/txt.list`
do
    mv $f  $f.bak
done

#find /123/ -type f -name *.txt |xargs -i mv {} {}.bak 
#find /123/ -type f -name *.txt -exec mv {} {}.bak \;

for f in `cat /tmp/txt.list`
do
    echo $f.bak
done > /tmp/txt.bak.list 

tar -czvf 123.tar.gz `cat /tmp/txt.bak.list |xargs `

for f in `cat /tmp/txt.list`
do 
    mv $f.bak $f
done 
6、写一个脚本,判断本机的80端口(假如服务为httpd)是否开启着,如果开启着什么都不做,如果发现端口不存在,那么重启一下httpd服务,

并发邮件通知你自己。脚本写好后,可以每一分钟执行一次,也可以写一个死循环的脚本,30s检测一次。

核心要点

* 检测80端口使用nmap -p 80 127.0.0.1或者netstat -lntp|grep -w 80

* 重启httpd服务的命令要知道

* 发邮件脚本依然使用mail.py

bash 复制代码
#!/bin/bash
m=123@123.com
while :
do
    n=`netstat -lntp |grep ':80 '|wc -l`
    if [ $n -eq 0 ]
    then
        /usr/local/apache2/bin/apachectl -k restart 2>/tmp/apache.err
        python mail.py $m "80端口关闭" "已经重启httpd服务"
        pn=`pgrep -l httpd|wc -l`
	if [ $pn -eq 0 ]
	then
	    python mail.py $m "httpd重启失败" "`head -1 /tmp/apache.err`"
	fi
    fi
    
    sleep 30
done
7、设计一个shell脚本来备份数据库,首先在本地服务器上保存一份数据,然后再远程拷贝一份,本地保存一周的数据,远程保存一个月。

假定,我们知道mysql root账号的密码,要备份的库为discuz,本地备份目录为/bak/mysql, 远程服务器ip为192.168.123.30,

远程提供了一个rsync服务,备份的地址是 192.168.123.30::backup . 写完脚本后,需要加入到cron中,每天凌晨3点执行。

核心要点

* 备份数据库的命令

* 同步到远程去的命令

* 本地一周,可以用date +%w做为后缀,远程一个月可以用date +%d做为后缀

bash 复制代码
#!/bin/bash
d1=`date +%w`
d2=`date +%d`
local_bakdir=/bak/mysql
remote_bakdir=192.168.123.30::backup

exec 1> /tmp/mysqlbak.log  2>/tmp/mysqlbak.err
echo "mysql bakcup begin at `date`"
mysqldump -uroot -pxxxx discz > $local_bakdir/discuz.sql.$d1
rsync -az $local_bakdir/discuz.sql.$d1 $remote_bakdir/discuz.sql.$d2
echo "mysql backup end at `date`"
8、服务器上跑的是LNMP环境,近期总是有502现象。502为网站访问的状态码,200正常,502错误是nginx最为普遍的错误状态码。

由于502只是暂时的,并且只要一重启php-fpm服务则502消失,但不重启的话,则会一直持续很长时间。

所以有必要写一个监控脚本,监控访问日志的状态码,一旦发生502,则自动重启一下php-fpm。

我们设定:

1)access_log /data/log/access.log

2)脚本死循环,每10s检测一次(假设每10s钟的日志条数为300左右)

3)重启php-fpm的方法是 /etc/init.d/php-fpm restart

核心要点

* 用curl检测状态码是否是502或者通过分析访问日志判断状态码的比率

* 重启php-fpm服务的命令

bash 复制代码
#!/bin/bash
log=/data/log/access.log
while :
do
502_n=`tail -n 300 $log |grep -c ' 502 '`
if [ -z "$502_n" ]
then
    exit
fi

if [ $502_n -gt 100 ]
then
    /etc/init.d/php-fpm restart >/dev/null 2>/tmp/php-fpm.err
    fpm_p_n=`pgrep -l php-fpm|wc -l`
    if [ $fpm_p_n -eq 0 ]
    then
        python mail.py xxx@xx.com "php-fpm重启失败" "`head -1 /tmp/php-fpm.err`"
        exit
    fi
fi
sleep 10
done
9、把一个文本文档的前5行中包含字母的行删除掉,同时把6到10行中的全部字母删除掉。

核心要点

sed命

bash 复制代码
#!/bin/bash
sed -n '1,5'p 1.txt |sed '/[a-zA-Z]/d'
sed '1,5d' 1.txt |sed '1,5s/[a-zA-Z]//g'
10、用shell打印下面这句话中字母数小于6的单词。Bash also interprets a number of multi-character options.

核心要点

* for循环遍历所有单词

* wc -L获取字符串长度

bash 复制代码
#!/bin/bash
c="Bash also interprets a number of multi-character options."
n=`echo $c|awk -F '[ +-.]' '{print NF}'`
for ((i=1;i<$n;i++))
do
    l=`echo $c|awk -F '[ +-.]' -v j=$i '{print $j}'|wc -L`
    if [ $l -lt 6 ]
    then
        echo $c|awk -F '[ +-.]' -v j=$i '{print $j}'
    fi
done
11、写一个脚本实现如下功能:

输入一个数字,然后运行对应的一个命令。

显示命令如下:

*cmd meau** 1 - date 2 - ls 3 - who 4 - pwd

当输入1时,会运行date, 输入2时运行ls, 以此类推。

核心要点

* case判断

bash 复制代码
#!/bin/bash
echo "*cmd meau**  1 - date 2 - ls 3 - who 4 - pwd"
read -p "Please input a number: " n
if [ -z "$n" ]
then
    echo "请输入一个纯数字,范围1-4."
    exit
fi

n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
then
    echo "请输入一个纯数字,范围1-4."
    exit
fi

case $n in 
    1)
	date
	;;
    2)
	ls
	;;
    3)
	who
	;;
    4)
	pwd
	;;
    *)
	echo "请输入1-4的数字"
        ;;
esac
12、用shell脚本实现如下需求:

添加user_00 -- user_09 10个用户,并且给他们设置一个随机密码,密码要求10位包含大小写字母以及数字,注意需要把每个用户的密码记录到一个日志文件里。

提示:

  1. 随机密码使用命令 mkpasswd

  2. 在脚本中给用户设置密码,可以使用echo 然后管道passwd命令

核心要点

* seq实现数字递增

* mkpasswd产生随机字符

bash 复制代码
#!/bin/bash
for i in `seq -w 00 09`
do
    useradd user_$i
    p=`mkpasswd -l 10 -s 0 `
    echo "user_$i $p" >> /tmp/pass.tmp
    echo $p |passwd --stdin user_$i
done
13、在服务器上,写一个监控脚本,要求如下:
  1. 每隔10s去检测一次服务器上的httpd进程数,如果大于等于500的时候,就需要自动重启一下apache服务,并检测启动是否成功?

  2. 若没有正常启动还需再一次启动,最大不成功数超过5次则需要立即发邮件通知管理员,并且以后不需要再检测!

  3. 如果启动成功后,1分钟后再次检测httpd进程数,若正常则重复之前操作(每隔10s检测一次),若还是大于等于500,那放弃重启并需要发邮件给管理员,然后自动退出该脚本。假设其中发邮件脚本为之前使用的mail.py

核心要点

* pgrep -l httpd或者ps -C httpd --no-heading检查进程

* for循环5次计数器

bash 复制代码
#!/bin/bash
check_service()
{
    n=0
    for i in `seq 1 5`
    do
        /usr/local/apache2/bin/apachectl restart 2>/tmp/apache.err
        if [ $? -ne 0 ]
        then
            n=$[$n+1]
        else
            break
        fi
    done
    if [ $n -eq 5 ]
    then
        ##下面的mail.py参考https://coding.net/u/aminglinux/p/aminglinux-book/git/blob/master/D22Z/mail.py
        python mai.py "123@qq.com" "httpd service down" `cat /tmp/apache.err`
        exit
    fi
}   
while true
do
    t_n=`ps -C httpd --no-heading |wc -l`
    if [ $t_n -ge 500 ]
    then
        /usr/local/apache2/bin/apachectl restart
        if [ $? -ne 0 ]
        then
            check_service
        fi
        sleep 60
        t_n=`ps -C httpd --no-heading |wc -l`
        if [ $t_n -ge 500 ]
        then
            python mai.py "123@qq.com" "httpd service somth wrong" "the httpd process is busy."
            exit
        fi
    fi
    sleep 10
done
14、需求: 根据web服务器上的访问日志,把一些请求量非常高的ip给拒绝掉!并且每隔半小时把不再发起请求或者请求量很小的ip给解封。

假设:

  1. 一分钟内请求量高于100次的IP视为不正常请求。

  2. 访问日志路径为/data/logs/access_log。

用第2例中的1.log作为演示日志

核心要点

* 统计ip访问次数,排序

* 如何标记每隔半小时

* iptables计数器是一个重要的判断指标

* 函数(封IP、解封IP)

bash 复制代码
#!/bin/bash
block_ip()
{
t1=`date -d "-1 min" +%Y:%H:%M`
log=/data/logs/access_log

egrep "$t1:[0-9]+" $log > /tmp/tmp_last_min.log
awk '{print $1}' /tmp/tmp_last_min.log |sort -n |uniq -c|sort -n |awk '$1>100 {print $2}' > /tmp/bad_ip.list 
n=`wc -l /tmp/bad_ip.list|awk '{print $1}'`
if [ $n -ne 0 ]
then
    for ip in `cat /tmp/bad_ip.list`
    do
	iptables -I INPUT -s $ip -j REJECT
    done
fi
}

unblock_ip()
{
    iptables -nvL INPUT|sed '1d' |awk '$1<5 {print $8}' > /tmp/good_ip.list
    n=`wc -l /tmp/good_ip.list|awk '{print $1}'`
    if [ $n -ne 0 ]
    then
    for ip in `cat /tmp/good_ip.list`
    do
	iptables -D INPUT -s $ip -j REJECT
    done
    fi
    iptables -Z
}

t=`date +%M`
if [ $t == "00" ] || [ $t == "30" ]
then
   unblock_ip
   block_ip
else
   block_ip
fi
15、请仔细查看如下几个数字的规律,并使用shell脚本输出后面的十个数字。

10 31 53 77 105 141 .......

核心要点

* 计算两个数值之间的差值

bash 复制代码
#!/bin/bash
x=10
y=21
for i in `seq 0 15`
do 
    echo $x
    x=$[$x+$y]
    z=$[2**$i]
    y=$[$y+$z]
done
16、写个shell,看看你的Linux系统中是否有自定义用户(普通用户),若是有,一共有几个?
bash 复制代码
#!/bin/bash
v=`awk -F 'release ' '{print $2}' /etc/redhat-release |cut -d '.' -f1`
user()
{
      if [ $1 -eq 0 ]
      then
          echo "系统没有自定义的用户"
      else
          echo "系统存在自定义用户,有$1个"
      fi
}
case $v in 
  5|6)
      n=`awk -F ':' '$3>=500' /etc/passwd|wc -l`
      user $n
  ;;
  7)
      n=`awk -F ':' '$3>=1000' /etc/passwd|wc -l`
      user $n
  ;;
  *)
     echo "脚本出错."
  ;;
esac 
17、写一个shell脚本,检测所有磁盘分区使用率和inode使用率并记录到以当天日期为命名的日志文件里,当发现某个分区容量或者inode使用量大于85%时,发邮件通知你自己。
bash 复制代码
#!/bin/bash
dir=/tmp/disk
d=`date +%F`
mail=123@123.com

[ -d $dir ] || mkdir $dir

df >> $dir/$d.log
df -i >> $dir/$d.log

df|sed '1d' |awk -F ' +|%' '$5>=85 {print $7}' > $dir/df.tmp
df -i|sed '1d' |awk -F ' +|%' '$5>=85 {print $7}' > $dir/df_i.tmp

n1=`wc -l $dir/df.tmp|awk '{print $1}'`
n2=`wc -l $dir/df_i.tmp|awk '{print $1}'`

tag=0
if [ $n1 -gt 0 ]
then
    if [ $n2 -gt 0 ]
    then
	tag=11
    else
	tag=10
    fi
else
    if [ $n2 -gt 0 ]
    then
	tag=01
    else
	tag=00
    fi
fi

case $tag in
    11)
	python mail.py $mail "磁盘空间和inode使用率高于85%" "`cat $dir/df.tmp $dir/df_i.tmp|xargs`"
        ;;
    10)
	python mail.py $mail "磁盘空间使用率高于85%" "`cat $dir/df.tmp|xargs`"
	;;
    01)
	python mail.py $mail "磁盘inode使用率高于85%" "`cat $dir/df_i.tmp|xargs`"
	;;
    *)
	;;
esac
18、有一台服务器作为web应用,有一个目录(/data/web/attachment)不定时地会被用户上传新的文件,但是不知道什么时候会上传。所以,需要我们每5分钟做一次检测是否有新文件生成。

请写一个shell脚本去完成检测。检测完成后若是有新文件,还需要将新文件的列表输出到一个按年、月、日、时、分为名字的日志里。

bash 复制代码
#!/bin/bash
basedir=/data/web/attachment
t=`date +%Y%m%d%H%M`

find $basedir/ -type f -mmin -5 > /tmp/file.list
n=`wc -l /tmp/file.list|awk '{print $1}'`
if [ $n -lt 0 ]
then
   mv /tmp/file.list /tmp/$t.list
fi
19、写一个shell脚本来看看你使用最多的命令是哪些,列出你最常用的命令top10。
bash 复制代码
cat ~/.bash_history |sort |uniq -c |sort -nr |head
20、假如需要每小时都去执行一个脚本。在脚本中实现这样的功能,当时间是0点和12点时,需要将目录/data/log/下的文件全部清空,

注意只能清空文件内容而不能删除文件。而其他时间只需要统计一下每个文件的大小,一个文件一行,输出到一个按日期和时间为名字的日志里。

需要考虑/data/log/目录下的二级、三级、... 等子目录里面的文件。

bash 复制代码
#!/bin/bash
dir=/tmp/log_stat
t=`date +%d%H`
t1=`date +%H`
logdir=/data/log

[ -d $dir ] || mkdir $dir
[ -f $dir/$t.log ] && rm -f $dir/$t.log

if [ $t == "00" -o $t == "12" ]
then
    for f in `find $logdir/ -type f`
    do
	> $f
    done
else
    for f in `find $logdir/ -type f`
    do
	du -sh $f >> $dir/$t.log
    done
fi
21、计算文档a.txt中每一行中出现的数字个数并且要计算一下整个文档中一共出现了几个数字。例

如a.txt内容如下:

12aa*lkjskdj

alskdflkskdjflkjj

我们脚本名字为 ncount.sh, 运行它时:

bash ncount.sh a.txt

输出结果应该为:

2

0

sum:2

bash 复制代码
#!/bin/bash
sum=0
while read line
do
    line_n=`echo $line|sed 's/[^0-9]//g'|wc -L`
    echo $line_n
    sum=$[$sum+$line_n]
done < $1
echo "sum:$sum"
22、有两台Linux服务器A和B,假如A可以直接ssh到B,不用输入密码。A和B都有一个目录叫做/data/web/ 这下面有很多文件,

当然我们不知道具体有几层子目录,假若之前A和B上该目录下的文件都是一模一样的。

但现在不确定是否一致了。固需要我们写一个脚本实现这样的功能,检测A机器和B机器/data/web/目录下文件的异同,我们以A机器上的文件作为标准。

比如,假若B机器少了一个a.txt文件,那我们应该能够检测出来,或者B机器上的b.txt文件有过改动,我们也应该能够检测出来(B机器上多了文件不用考虑)。

bash 复制代码
#!/bin/bash
dir=/data/web
[ -f /tmp/md5.list ] && rm -f /tmp/md5.list
find $dir/ -type f > /tmp/file.list
while read line 
do
    md5sum $line  >> /tmp/md5.list
done < /tmp/file.list

scp /tmp/md5.list B:/tmp/
[ -f /tmp/check_md5.sh ] && rm -f /tmp/check_md5.sh

cat >/tmp/check_md5.sh << EOF
#!/bin/bash
dir=/data/web
n=\`wc -l /tmp/md5.list|awk '{print \$1}'\`
for i in \`seq 1 \$n\`
do
    file_name=\`sed -n "\$i"p /tmp/md5.list |awk '{print \$1}'\`
    md5=\`sed -n "\$i"p /tmp/md5.list|awk '{print \$2}'\`
    if [ -f \$file_name ]
    then
	md5_b=\`md5sum \$file_name\`
	if [\$md5_b != \$md5 ]
	then
	    echo "\$file_name changed."
	fi
    else
	echo "\$file_name lose."
    fi
done
EOF
scp /tmp/check_md5.sh B:/tmp/
ssh B "/bin/bash /tmp/check_md5.sh"
23、写一个脚本,检测你的网络流量,并记录到一个日志里。需要按照如下格式,并且一分钟统计一次(只需要统计外网网卡,假设网卡名字为eth0):

2020-08-04 01:11

eth0 input: 1000bps

eth0 output : 200000bps

2020-08-04 01:12

eth0 input: 1000bps

eth0 output : 200000bps

提示:使用sar -n DEV 1 59 这样可以统计一分钟的平均网卡流量,只需要最后面的平均值。另外,注意换算一下,1Byte=8bit

bash 复制代码
#!/bin/bash
logdir=/tmp/sar_log
file=$logdir/`date +%d%H`.log
t=`date +"%F %H:%M"`

[ -d $logdir ] || mkdir -p $logdir
LANG=en
sar -n DEV 1 5 |grep eth0 |grep "Average" > /tmp/sar.tmp

exec >>$file
echo "$t" 
awk '{print "eth0 input:",$5*8000"bps""\n""eth0 output:",$6*8000"bps"}' /tmp/sar.tmp 
echo "#### ###################" 
24、一台机器负载高,top查看有很多sh的进程,然后top -c查看可以看到对应的进程命令是sh -c /bin/clearnen.sh 。

经分析后发现是因为该脚本执行时间太长,导致后续执行时,上次的脚本还未执行结束。写一个脚本批量杀死所有sh的进程。

bash 复制代码
#!/bin/bash
for pid in `ps aux |grep clearnen.sh |awk '{print $2}'` 
do 
    echo $pid
    kill -9 $pid
done
25、写一个脚本判断你的Linux服务器里是否开启web服务?(监听80端口)如果开启了,请判断出跑的是什么服务,是httpd呢还是nginx又或者是其他的什么?
bash 复制代码
#!/bin/bash
n=`netstat -lntp |grep ':80 '|wc -l`
if [ $n -eq 0 ]
then
    echo "It not listen port 80"
else
    ser=`netstat -lntp |grep ':80 '|awk -F '/' '{print $NF}'|sed 's/ //g'`
    echo "It is listenning port 80, and the service is $ser."
fi
相关推荐
AlfredZhao8 小时前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户97183563346614 小时前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪15 小时前
linux 拷贝文件或目录到指定的位置
linux
大树881 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠1 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质1 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush41 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
VidDown1 天前
VidDown 工具站:免费、本地优先的开发者工具箱
javascript·编辑器·音视频·视频编解码·视频
载数而行5201 天前
Linux 11 动态监控指令top
linux
Inhand陈工1 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信