最近练习的一些经典shell脚本实战30个(代码片段)

抛物线. 抛物线.     2023-03-21     273

关键词:

首先,对于运维行业,不管是云计算运维还是linux运维都不开shell的使用,那么最近收集实战了一些很有用的shell脚本实例,这里分享给大家。

目录:
1、获取随机字符串或数字
2、定义一个颜色输出字符串函数
3、批量创建用户
4、检查软件包是否安装
5、检查服务状态
6、检查主机存活状态
7、监控CPU、内存和硬盘利用率
8、批量主机磁盘利用率监控
9、检查网站可用性
10、检查MySQL主从同步状态
11、iptables自动屏蔽访问网站频繁的IP
12、判断用户输入的是否为IP地址
13、判断用户输入的是否为数字
14、给定目录找出包含关键字的文件
15、监控目录,将新创建的文件名追加到日志中
16、给用户提供多个网卡选择
17、查看网卡实时流量
18、MySQL数据库备份
19、Nginx服务管理脚本
20、用户根据菜单选择要连接的Linux主机
21、从FTP服务器下载文件
22、连续输入5个100以内的数字,统计和、最小和最大
23、将结果分别赋值给变量
24、批量修改文件名
25、统计当前目录中以.html结尾的文件总大
26、扫描主机端口状态
27、Expect实现SSH免交互执行命令
28、批量修改服务器用户密码
29、打印乘法口诀
30、getopts工具完善脚本命令行参数

开头加解释器:#!/bin/bash
语法缩进,使用四个空格;多加注释说明。
命名建议规则:变量名大写、局部变量小写,函数名小写,名字体现出实际作用。
默认变量是全局的,在函数中变量local指定为局部变量,避免污染其他作用域。
有两个命令能帮助我调试脚本:set -e 遇到执行非0时退出脚本,set-x 打印执行过程。
写脚本一定先测试再到生产上。

1.获取随机字符串或数字

方法1:
# echo $RANDOM |md5sum |cut -c 1-8
471b94f2
方法2:
# openssl rand -base64 4
vg3BEg==
方法3:
# cat /proc/sys/kernel/random/uuid |cut -c 1-8
ed9e032c
  1. 获取随机8位数字
方法1:
# echo $RANDOM |cksum |cut -c 1-8
23648321
方法2:
# openssl rand -base64 4 |cksum |cut -c 1-8       #cksum:打印CRC效验和统计字节
38571131
方法3:
# date +%N |cut -c 1-8     
69024815
  1. 定义一个颜色输出字符串函数
方法1:
function echo_color() 
    if [ $1 == "green" ]; then
        echo -e "\\033[32;40m$2\\033[0m"
    elif [ $1 == "red" ]; then
        echo -e "\\033[31;40m$2\\033[0m"
    fi

方法2:
function echo_color() 
    case $1 in
        green)
            echo -e "[32;40m$2[0m"
            ;;
        red)
            echo -e "[31;40m$2[0m" 
            ;;
        *) 
            echo "Example: echo_color red string"
    esac



使用方法:echo_color green "test"
function关键字定义一个函数,可加或不加。

3、批量创建用户

#!/bin/bash
DATE=$(date +%F_%T)
USER_FILE=user.txt
echo_color()
    if [ $1 == "green" ]; then
        echo -e "[32;40m$2[0m"
    elif [ $1 == "red" ]; then
        echo -e "[31;40m$2[0m"
    fi

# 如果用户文件存在并且大小大于0就备份
if [ -s $USER_FILE ]; then
    mv $USER_FILE $USER_FILE-$DATE.bak
    echo_color green "$USER_FILE exist, rename $USER_FILE-$DATE.bak"
fi
echo -e "User	Password" >> $USER_FILE
echo "----------------" >> $USER_FILE
for USER in user1..10; do
    if ! id $USER &>/dev/null; then
        PASS=$(echo $RANDOM |md5sum |cut -c 1-8)
        useradd $USER
        echo $PASS |passwd --stdin $USER &>/dev/null
        echo -e "$USER	$PASS" >> $USER_FILE
        echo "$USER User create successful."
    else
        echo_color red "$USER User already exists!"
    fi
done
  1. 检查软件包是否安装
#!/bin/bash
if rpm -q sysstat &>/dev/null; then
    echo "sysstat is already installed."
else
    echo "sysstat is not installed!"
fi

6、检查主机存活状态

方法1:将错误IP放到数组里面判断是否ping失败三次
#!/bin/bash  
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
for IP in $IP_LIST; do
    NUM=1
    while [ $NUM -le 3 ]; do
        if ping -c 1 $IP > /dev/null; then
            echo "$IP Ping is successful."
            break
        else
            # echo "$IP Ping is failure $NUM"
            FAIL_COUNT[$NUM]=$IP
            let NUM++
        fi
    done
    if [ $#FAIL_COUNT[*] -eq 3 ];then
        echo "$FAIL_COUNT[1] Ping is failure!"
        unset FAIL_COUNT[*]
    fi
done


方法2:将错误次数放到FAIL_COUNT变量里面判断是否ping失败三次


#!/bin/bash  
IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
for IP in $IP_LIST; do
    FAIL_COUNT=0
    for ((i=1;i<=3;i++)); do
        if ping -c 1 $IP >/dev/null; then
            echo "$IP Ping is successful."
            break
        else
            # echo "$IP Ping is failure $i"
            let FAIL_COUNT++
        fi
    done
    if [ $FAIL_COUNT -eq 3 ]; then
        echo "$IP Ping is failure!"
    fi
done


方法3:利用for循环将ping通就跳出循环继续,如果不跳出就会走到打印ping失败
#!/bin/bash
ping_success_status() 
    if ping -c 1 $IP >/dev/null; then
        echo "$IP Ping is successful."
        continue
    fi

IP_LIST="192.168.18.1 192.168.1.1 192.168.18.2"
for IP in $IP_LIST; do
    ping_success_status
    ping_success_status
    ping_success_status
    echo "$IP Ping is failure!"
done

7、监控CPU、内存和硬盘利用率

1)CPU
借助vmstat工具来分析CPU统计信息。
#!/bin/bash
DATE=$(date +%F" "%H:%M)
IP=$(ifconfig eth0 |awk -F  [ :]+   /inet addr/print $4 )  # 只支持CentOS6
MAIL="example@mail.com"
if ! which vmstat &>/dev/null; then
    echo "vmstat command no found, Please install procps package." 
    exit 1
fi
US=$(vmstat |awk  NR==3print $13 )
SY=$(vmstat |awk  NR==3print $14 )
IDLE=$(vmstat |awk  NR==3print $15 )
WAIT=$(vmstat |awk  NR==3print $16 )
USE=$(($US+$SY))
if [ $USE -ge 50 ]; then
    echo "
    Date: $DATE
    Host: $IP
    Problem: CPU utilization $USE
    " | mail -s "CPU Monitor" $MAIL
fi

2)内存

#!/bin/bash
DATE=$(date +%F" "%H:%M)
IP=$(ifconfig eth0 |awk -F  [ :]+   /inet addr/print $4 )  
MAIL="example@mail.com"
TOTAL=$(free -m |awk  /Mem/print $2 )
USE=$(free -m |awk  /Mem/print $3-$6-$7 )
FREE=$(($TOTAL-$USE))
# 内存小于1G发送报警邮件
if [ $FREE -lt 1024 ]; then
    echo "
    Date: $DATE
    Host: $IP
    Problem: Total=$TOTAL,Use=$USE,Free=$FREE
    " | mail -s "Memory Monitor" $MAIL
fi

3)硬盘
#!/bin/bash
DATE=$(date +%F" "%H:%M)
IP=$(ifconfig eth0 |awk -F  [ :]+   /inet addr/print $4 )  
MAIL="example@mail.com"
TOTAL=$(fdisk -l |awk -F [: ]+   BEGINOFS="="/^Disk /dev/printf "%s=%sG,",$2,$3 )
PART_USE=$(df -h |awk  BEGINOFS="="/^/dev/print $1,int($5),$6 )
for i in $PART_USE; do
    PART=$(echo $i |cut -d"=" -f1)
    USE=$(echo $i |cut -d"=" -f2)
    MOUNT=$(echo $i |cut -d"=" -f3)
    if [ $USE -gt 80 ]; then
        echo "
        Date: $DATE
        Host: $IP
        Total: $TOTAL
        Problem: $PART=$USE($MOUNT)
        " | mail -s "Disk Monitor" $MAIL
    fi
done




8、批量主机磁盘利用率监控

前提监控端和被监控端SSH免交互登录或者密钥登录。
写一个配置文件保存被监控主机SSH连接信息,文件内容格式:IP User Port

#!/bin/bash
HOST_INFO=host.info
for IP in $(awk  /^[^#]/print $1  $HOST_INFO); do
    USER=$(awk -v ip=$IP  ip==$1print $2  $HOST_INFO)
    PORT=$(awk -v ip=$IP  ip==$1print $3  $HOST_INFO)
    TMP_FILE=/tmp/disk.tmp
    ssh -p $PORT $USER@$IP  df -h  > $TMP_FILE
    USE_RATE_LIST=$(awk  BEGINOFS="="/^/dev/print $1,int($5)  $TMP_FILE)
    for USE_RATE in $USE_RATE_LIST; do
        PART_NAME=$USE_RATE%=*
        USE_RATE=$USE_RATE#*=
        if [ $USE_RATE -ge 80 ]; then
            echo "Warning: $PART_NAME Partition usage $USE_RATE%!"
        fi
    done
done

9、检查网站可用性

1)检查URL可用性

方法1:
check_url() 
    HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%http_code" $1)
    if [ $HTTP_CODE -ne 200 ]; then
        echo "Warning: $1 Access failure!"
    fi

方法2:
check_url() 
if ! wget -T 10 --tries=1 --spider $1 >/dev/null 2>&1; then  
#-T超时时间,--tries尝试1次,--spider爬虫模式
        echo "Warning: $1 Access failure!"
    fi


使用方法:check_url www.baidu.com

2)判断三次URL可用性
思路与上面检查主机存活状态一样。
方法1:利用循环技巧,如果成功就跳出当前循环,否则执行到最后一行

#!/bin/bash  
check_url() 
    HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%http_code" $1)
    if [ $HTTP_CODE -eq 200 ]; then
        continue
    fi

URL_LIST="www.baidu.com www.agasgf.com"
for URL in $URL_LIST; do
    check_url $URL
    check_url $URL
    check_url $URL
    echo "Warning: $URL Access failure!"
done

方法2:错误次数保存到变量

#!/bin/bash  
URL_LIST="www.baidu.com www.agasgf.com"
for URL in $URL_LIST; do
    FAIL_COUNT=0
    for ((i=1;i<=3;i++)); do
        HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%http_code" $URL)
        if [ $HTTP_CODE -ne 200 ]; then
            let FAIL_COUNT++
        else
            break
        fi
    done
    if [ $FAIL_COUNT -eq 3 ]; then
        echo "Warning: $URL Access failure!"
    fi
done

方法3:错误次数保存到数组

#!/bin/bash  
URL_LIST="www.baidu.com www.agasgf.com"
for URL in $URL_LIST; do
    NUM=1
    while [ $NUM -le 3 ]; do
        HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%http_code" $URL)
        if [ $HTTP_CODE -ne 200 ]; then
            FAIL_COUNT[$NUM]=$IP  #创建数组,以$NUM下标,$IP元素
            let NUM++
        else
            break
        fi
    done
    if [ $#FAIL_COUNT[*] -eq 3 ]; then
        echo "Warning: $URL Access failure!"
        unset FAIL_COUNT[*]    #清空数组
    fi
done


10、检查MySQL主从同步状态


#!/bin/bash  
USER=bak
PASSWD=123456
IO_SQL_STATUS=$(mysql -u$USER -p$PASSWD -e  show slave statusG  |awk -F:  /Slave_.*_Running/gsub(": ",":");print $0 )  #gsub去除冒号后面的空格
for i in $IO_SQL_STATUS; do
    THREAD_STATUS_NAME=$i%:*
    THREAD_STATUS=$i#*:
    if [ "$THREAD_STATUS" != "Yes" ]; then
        echo "Error: MySQL Master-Slave $THREAD_STATUS_NAME status is $THREAD_STATUS!"
    fi
done

11、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]++ENDfor(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]++ENDfor(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]++ENDfor(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)]++ENDfor(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

12、判断用户输入的是否为IP地址

方法1:
#!/bin/bash
function check_ip()
    IP=$1
    VALID_CHECK=$(echo $IP|awk -F. '$1<=255&&$2<=255&&$3<=255&&$4<=255print "yes"')
    if echo $IP|grep -E "^[0-9]1,3\\.[0-9]1,3\\.[0-9]1,3\\.[0-9]1,3$">/dev/null; then
        if [ $VALID_CHECK == "yes" ]; then
            echo "$IP available."
        else
            echo "$IP not available!"
        fi
    else
        echo "Format error!"
    fi

check_ip 192.168.1.1
check_ip 256.1.1.1

方法2:
#!/bin/bash
function check_ip()
    IP=$1
    if [[ $IP =~ ^[0-9]1,3\\.[0-9]1,3\\.[0-9]1,3\\.[0-9]1,3$ ]]; then
        FIELD1=$(echo $IP|cut -d. -f1)
        FIELD2=$(echo $IP|cut -d. -f2)
        FIELD3=$(echo $IP|cut -d. -f3)
        FIELD4=$(echo $IP|cut -d. -f4)
        if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 ]; then
            echo "$IP available."
        else
            echo "$IP not available!"
        fi
    else
        echo "Format error!"
    fi

check_ip 192.168.1.1
check_ip 256.1.1.1

增加版:
加个死循环,如果IP可用就退出,不可用提示继续输入,并使用awk判断。
#!/bin/bash
function check_ip()
    local IP=$1
    VALID_CHECK=$(echo $IP|awk -F. '$1<=255&&$2<=255&&$3<=255&&$4<=255print "yes"')
    if echo $IP|grep -E "^[0-9]1,3\\.[0-9]1,3\\.[0-9]1,3\\.[0-9]1,3$" >/dev/null; then
        if [ $VALID_CHECK == "yes" ]; then
            return 0
        else
            echo "$IP not available!"
            return 1
        fi
    else
        echo "Format error! Please input again."
        return 1
    fi

while true; do
    read -p "Please enter IP: " IP
    check_ip $IP
    [ $? -eq 0 ] && break || continue
done



13、判断用户输入的是否为数字

方法1:
#!/bin/bash
if [[ $1 =~ ^[0-9]+$ ]]; then
    echo "Is Number."
else
    echo "No Number."
fi

方法2:
#!/bin/bash
if [ $1 -gt 0 ] 2>/dev/null; then
    echo "Is Number."
else
    echo "No Number."
fi

方法3:

#!/bin/bash
echo $1 |awk 'print $0~/^[0-9]+$/?"Is Number.":"No Number."'  #三目运算符
12.14 找出包含关键字的文件
DIR=$1
KEY=$2
for FILE in 查看详情  

10个面试及实战常用shell脚本(代码片段)

...量,避免污染其他作用域。5)有两个命令能帮助我调试脚本:set-e遇到执行非0时退出脚本,set-x打印执行过程。6)写脚本一定先测试再到生产上。1获取随机字符串或数字获取随机8 查看详情

shell脚本上

...年的运维老年还是写不出来,那就是没主动找需求,缺乏练习,缺乏经验。针对以上问题,总结了30个生产环境中经典的Shell脚本,通过这些需求案例,希望能帮助大家提升Shell编写思路,掌握编写技巧。|先了解下编写Shell过程中... 查看详情

linux之shell脚本实战统计linux进程相关数量信息(代码片段)

【Linux之shell脚本实战】统计Linux进程相关数量信息一、脚本要求二、检查本地服务器状态1.检查系统版本2.检查系统内核版本三、配置脚本注释模板1.编辑.vimrc文件2.检查模板生效情况四、编写ps_aa.sh脚本五、查看脚本效果一、脚... 查看详情

4个python经典项目实战,练手必备哦!

...,接下来,和大家介绍下Python练手的实战项目。Python项目练习一:即时标记这是《Python基础教程》后面的实践,照着写写,一方面是来熟悉Python的代码方式,另一方面是练习使用Python中的基本的以及非基本的语法,做到熟能生巧... 查看详情

shell脚本学习-练习写一个脚本2(代码片段)

 #1.依次展示/var目录下的对象,并说明是文件或者目录。格式如:Hello,$file.#2.统计一个有多少个文件。#!/bin/bash#ProgramDescription:#Author:Createdbyctu_lzq#Date:2018/11/15list=`ls/var|awk‘print$1‘`num=`ls/var|wc-l`foriin$list;doif[-f 查看详情

shell脚本实战-部署nginx脚本(代码片段)

前言我们写脚本一定要从最简单的脚本开始,循序渐进,不要一上来就想着用for循环,用函数,而应该在写的过程中,突然发现这里可以改为函数,那里可以加个循环。一键部署NginxWEB平台(v1)版... 查看详情

shell脚本实战-部署nginx脚本(代码片段)

前言我们写脚本一定要从最简单的脚本开始,循序渐进,不要一上来就想着用for循环,用函数,而应该在写的过程中,突然发现这里可以改为函数,那里可以加个循环。一键部署NginxWEB平台(v1)版... 查看详情

(vulnhub练习)--dc:8渗透实战(代码片段)

(Vulnhub练习)--DC:8渗透实战下载地址https://www.vulnhub.com/entry/dc-8,367/扫描主机netdiscover-ieth0-r192.168.100.0/24目标主机IP:192.168.100.160信息收集信息收集的步骤基本上差不多,可根据工具简单写个shell脚本#!/usr/bin/baship=192.168.100. 查看详情

每日一道shell练习(06)——检测端口服务(代码片段)

1.题目写一个脚本,判断本机的80端口(假设服务为httpd)是否开启着,如果开启着就什么都不做,如果发现端口不存在,那么重启一下httpd服务,并发邮件通知你自己。脚本写好后,每分钟执行一次,也可以写一个死循环的脚本... 查看详情

每日一道shell脚本练习(01)(代码片段)

0.引言准备开一个新坑,每天更新一道shell练习。因为shell脚本属于那种不练习就会生疏,甚至忘记的技能,所以,为了对抗遗忘阻力,我只能不断加强练习了。1.第一天练习题目【题目】请按照这样的日期格式(xxxx-xx-xx)每日生... 查看详情

(vulnhub练习)--hackme:1渗透实战(代码片段)

(Vulnhub练习)--HACKME:1渗透实战文章目录(Vulnhub练习)--HACKME:1渗透实战下载地址扫描主机目标主机IP:192.168.100.134信息收集nmap端口扫描指纹识别路径扫描开始测试SQL注入sqlmap手工注入superadmin用户登录文件上传直接一句话木马上传... 查看详情

练习脚本和一些可用脚本(更新中...)(代码片段)

零碎知识点开启一个脚本相当于开启一个子进程,变量不会继承注意()里面也会开启子进程,变量不会继承,如果想要作为一个整体要用。但是注意exit的返回值即使在()里面,但如果它是最后一个命令执行过后产生的,没... 查看详情

shell脚本练习实例详解(代码片段)

shell脚本练习实例文章目录shell脚本练习实例1、倒计时脚本2、创建用户脚本3、系统资源使用统计脚本4、数据库备份脚本5、swap分区自动创建脚本1、倒计时脚本题目1:编写10s倒计时脚本思路:这里需要使用for循环语句对... 查看详情

shell脚本经典题之函数应用(代码片段)

shell脚本经典题之函数应用文章目录shell脚本经典题之函数应用1、函数的概述:(1)函数的定义:(2)函数的使用:(3)函数的返回值:(4)函数的参数:2、shell函数例题--阶乘计算:3、shell函数--冒泡排序:4、... 查看详情

linux系统shell脚本之用户管理脚本实战(代码片段)

Linux系统shell脚本之用户管理脚本实战一、脚本要求二、脚本内容三、执行脚本1.正确执行脚本2.错误执行脚本一、脚本要求1.使用usage函数,列出该脚本的帮助选项2.检查该脚本的执行用户,若非root用户,直接退出3.该脚本可以管... 查看详情

linux系统编程-shell脚本基本使用(数组函数字符串处理)(代码片段)

...个例子程序,直接看例子程序理解。后面列出了一些练习题,结合前面的介绍的基本语法知识做一些练习,巩固Shell的基本语法使用。2.数组的定义与使用 查看详情

shell脚本之购物车清单脚本(代码片段)

想要提升shell脚本能力,练习必不可少。真正有效的练习方法之一就是穷举法。所谓的穷举法,就是把一个脚本练到极致。任何脚本都讲究循序渐进,先从最简单的功能开始,逐渐增加难度。在同一个难度的级别&#... 查看详情