美文网首页
shell 最使用实战整理

shell 最使用实战整理

作者: ketchup | 来源:发表于2021-05-31 12:55 被阅读0次

    shell 实战常用命令服务器系统一些配置初始化(centos7)
    发送告警邮件
    批量创建用户
    查看资源利用率
    找出占用CPU/内存过高的进程
    查看网卡实时流量
    监控批量服务器磁盘利用率
    --1.批量就需要免密登录
    --2.expec 免交互输入密码
    检测网站运行正常目录文件变化和同步
    mysql 备份监控
    MySQL 主从同步状态
    Nginx 访问日志分析
    自动屏蔽高访问IP
    LNMP环境搭建
    python 调用shell 命令

    服务器系统一些配置初始化(centos7)

    > cat /proc/version
    >
    > Linux version 5.4.0-72-generic (buildd@lcy01-amd64-019) (gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)) #80-Ubuntu SMP Mon Apr 12 17:35:00 UTC 2021
    >
    > cat /etc/lsb-release
    > DISTRIB_ID=Ubuntu
    > DISTRIB_RELEASE=20.04
    > DISTRIB_CODENAME=focal
    > DISTRIB_DESCRIPTION="Ubuntu 20.04.2 LTS"
    >
    >  cat /etc/redhat-release
    > CentOS Linux release 7.8.2003 (Core)
    
    #/bin/bash
    
    # 设置时区并同步时间
    ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    # 注意这种if 的写法是可以的, 如果grep没找到就返回Fasle, 还有可以用[] 做表达式
    if ! crontab -l |grep ntpdate &>/dev/null ; then
        # 同步时间 ntpdate time.windows.com
        # () 内作为一组去执行
        # |crontab 可以将前面的输入写到文件中
        # crontab -l 可以把前面的命令以新增的方式写入crontab, 不加他会覆盖所有之前的crontab
        (echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1";crontab -l) |crontab 
    fi
    
    # 禁用selinux, 不关闭可能会因为莫名其妙的权限问题导致服务不通
    # 这里匹配到SELINUX 这一行, 然后s/before/after 去替换, 和vim 里的:%s/before/after/g 一样
    sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config
    
    # 关闭防火墙
    # egrep 后面接正则匹配, 匹配到就为True
    # centos 7 用firewall 替代 iptables
    if egrep "7.[0-9]" /etc/redhat-release &>/dev/null; then
        systemctl stop firewalld
        systemctl disable firewalld
    elif egrep "6.[0-9]" /etc/redhat-release &>/dev/null; then
        service iptables stop
        chkconfig iptables off
    fi
    
    # 历史命令显示操作时间, 只要设置这个系统变量HISTTIMEFORMAT 即可, %F日期, %T时间
    # >> 增量写入
    if ! grep HISTTIMEFORMAT /etc/bashrc; then
        echo 'export HISTTIMEFORMAT="%F %T `whoami` "' >> /etc/bashrc
    fi
    
    # SSH超时时间
    if ! grep "TMOUT=600" /etc/profile &>/dev/null; then
        echo "export TMOUT=600" >> /etc/profile
    fi
    
    # 禁止root远程登录, 提前确定还有其他用户可以登录
    sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
    
    # 禁止定时任务向发送邮件
    # 如果定时任务没有加到重定向为空  >/dev/null 2>&1, 它的标准输出、错误都会向当前用户发送一封邮件, 存到 /var/mail/
    # mailto为空就不会发送
    # s/before/after/  替换
    sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab 
    
    # 设置最大打开文件数, 默认是1024, 并发数高的时候很容易达到
    # 将 soft hard 两行内容追加到 limits.conf中(*前面的空格也会写进去)
    # EOF 要顶到头, 否则会出错
    if ! grep "* soft nofile 65535" /etc/security/limits.conf &>/dev/null; then
    cat >> /etc/security/limits.conf << EOF
        * soft nofile 65535
        * hard nofile 65535
    EOF
    fi
    
    # 系统内核优化
    cat >> /etc/sysctl.conf << EOF
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_max_tw_buckets = 20480
    net.ipv4.tcp_max_syn_backlog = 20480  # 默认是128
    net.core.netdev_max_backlog = 262144  # 网卡最大的队列长度
    net.ipv4.tcp_fin_timeout = 20         # 四次挥手断开的一个超时时间
    EOF
    
    # 减少SWAP使用, 设置的是一个权重值, 值越大, 使用swap 的可能性越大,0 不使用
    # swap 比物理内存要慢很多, 但是也不要关闭他
    echo "0" > /proc/sys/vm/swappiness
    
    # 安装系统性能分析工具及其他
    yum install gcc make autoconf vim sysstat net-tools iostat iftop iotp lrzsz -y
    
    

    dos2unix

    有时候 windows 编辑的shell 文件在linux 中可能有格式、语法错误
    用dos2unix  转一下
    yum install dos2unix -y
    dos2unix shell_file.sh
    
    

    发送告警邮件

    系统默认发送邮件,用sendmail , 显示默认的发送人是主机名(会被当做垃圾邮件) 而且有延迟

    所有, 用外部邮箱服务器, 例如 163 (需要在邮箱设置中开启 SMTP)

    yum install mailx -y
    
    # yum install mailx
    # vi /etc/mail.rc  
    set from=test@163.com smtp=smtp.163.com
    set smtp-auth-user=test@163.com smtp-auth-password=123456
    set smtp-auth=login
    
    

    测试

    echo "this is a test content" | mail -s "subject name" test@163.com
    

    批量创建用户

    addusers.txt

    user1 pwd1
    user2 pwd2
    
    #!/bin/bash
    
    USERS_FILE=addusers.txt
    USERADD=/usr/sbin/useradd
    PASSWD=/usr/bin/passwd
    
    # 循环读文件
    while read line
    do
        # cut 通过 空格分隔, -f1 第一个
        USERNAME=`echo $line | cut -f1 -d ' '` 
        PASSWORD=`echo $line | cut -f2 -d ' '`
        $USERADD $USERNAME
        # $? 上一条命令的返回值, 0是 true, ne: not equal
        if [[ $? ne 0 ]]; then
            echo "$USERNAME has exited;skip set passwd"
        else
            echo "$PASSWORD | $PASSWD --stdin $USERNAME"
        fi
    done <$USERS_FILE
    
    
    if [ 1 -ne 1 ];then
    ...
    fi
        -eq:等于
        -ne:不等于
        -le:小于等于
        -ge:大于等于
        -lt:小于
        -gt:大于
        
        
    [root@VM-0-15-centos ~]# passwd --help
    Usage: passwd [OPTION...] <accountName>
      -x, --maximum=DAYS      maximum password lifetime (root only)
      -n, --minimum=DAYS      minimum password lifetime (root only)
      -w, --warning=DAYS      number of days warning users receives before password expiration (root only)
      -i, --inactive=DAYS     number of days after password expiration when an account becomes disabled (root only)
      -S, --status            report password status on the named account (root only)
      --stdin                 read new tokens from stdin (root only)
    

    升级版

    #!/bin/bash
    # 1.随机密码
    # 2.用户是否已经存在
    
    # 会接收所有的位置参数
    USER_LIST=$@
    USER_FILE=user.txt
    for USER in $USER_LIST; do
        # 通过id 查看用户是否存在
        if ! id $USER &>/dev/null; then
            # cut -c 
            PASS=$(echo $RANDOM |md5sum |cut -c 1-8)
            useradd $USER
            echo $PASS |passwd --stdin $USER &>/dev/null
            # 增量记录到文件
            echo "$USER   $PASS" >> $USER_FILE
            echo "$USER User create successful."
        else
            echo "$USER User already exists!"
        fi
    done
    
    

    重点

    [root@VM-0-15-centos ~]# id root
    uid=0(root) gid=0(root) groups=0(root)
    [root@VM-0-15-centos ~]# id ken
    id: ken: no such user
    
    # 生成随机值, 然后取他的 md5
    [root@VM-0-15-centos ~]# echo $RANDOM
    18466
    [root@VM-0-15-centos ~]# echo $RANDOM|md5sum
    7841fac0faa769963c0ade1107ff3e80  -
    
    
    [root@VM-0-15-centos ~]# echo "12345678" | cut -c 1-5
    12345
    
    
    # cut -d 通过空格分隔(其他分隔符也可以) 
    # cut -c 截取字符
    # -f1 取分隔后的第一个
    cut -f1 -d ' '
    
    
    [root@VM-0-15-centos ~]# echo {1..10}
    1 2 3 4 5 6 7 8 9 10
    
    

    grep

    # 在当前目录所有文件查询关键字 modified
    grep "modified" *
    
    # 查看关键字前后10行
    cat file_name.txt | grep "something" -C 10 
    
    # 监听本机网卡 eth0 端口8299 的请求, 然后查看 User-Agent 前后10行
    tcpdump -i eth0 -A  port 8299 |grep 'User-Agent' -C 10
    
    grep 关键字 -A 10 查看关键字后10行
               -B 10 查看关键字前10行
    

    查看资源利用率

    1.cpu 60%

    2.内存 利用率

    3.硬盘 利用率

    4.TCP 连接状态 (查看并发情况)

    可通过top 查看使用情况, 也可以使用vmstat

    wa 表示I/O wait CPU等待磁盘相应占用cpu 的百分比, 如果到了3%~5% 当前机器读写就会很慢

    [root@VM-0-15-centos ~]# vmstat
    procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
     4  0      0 618712  45888 189752    0    0    13    25  187  404  1  0 99  0  0
    
    netstat    
                -a all
                -t tcp
                -n numbric
                -p pid/name
    
    ESTABLISHED  说明正在建立通信, 相当于并发, 反应这台机器的网络连接承载量
    SYN_SENT        建立三次握手期间的状态, 还没正式建立完握手开始通信
    LISTEN          本地监听的服务
    
    [root@VM-0-15-centos ~]# netstat -atnp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      980/sshd
    tcp        0     28 10.206.0.15:22          218.82.138.5:62795      ESTABLISHED 31974/sshd: root@pt
    tcp        0      0 10.206.0.15:42786       169.254.0.55:5574       ESTABLISHED 1802/YDService
    
    #!/bin/bash
    
    function cpu() {
        NUM=1
        while [ $NUM -le 3 ]; do
            util=`vmstat |awk '{if(NR==3)print 100-$15"%"}'`
            user=`vmstat |awk '{if(NR==3)print $13"%"}'`
            sys=`vmstat |awk '{if(NR==3)print $14"%"}'`
            iowait=`vmstat |awk '{if(NR==3)print $16"%"}'`
            echo "CPU - 使用率: $util , 等待磁盘IO响应使用率: $iowait"
            let NUM++
            sleep 1
        done
    }
    
    function memory() {
        # printf 格式化输出 "%.1f" 保留一个小数点 后面要加逗号
        total=`free -m |awk '{if(NR==2)printf "%.1f",$2/1024}'`
        # $NF 表示最后一列
        used=`free -m |awk '{if(NR==2) printf "%.1f",($2-$NF)/1024}'`
        available=`free -m |awk '{if(NR==2) printf "%.1f",$NF/1024}'`
        echo "内存 - 总大小: ${total}G , 使用: ${used}G , 剩余: ${available}G"
    }
    
    function disk() {
        # awk '/^\/dev/{print $1}' 先匹配在输出, 匹配/dev开头的 然后/需要\转义
        fs=$(df -h |awk '/^\/dev/{print $1}')
        for p in $fs; do
            mounted=$(df -h |awk '$1=="'$p'"{print $NF}')
            size=$(df -h |awk '$1=="'$p'"{print $2}')
            used=$(df -h |awk '$1=="'$p'"{print $3}')
            
            used_percent=$(df -h |awk '$1=="'$p'"{print $5}')
            echo "硬盘 - 挂载点: $mounted , 总大小: $size , 使用: $used , 使用率: $used_percent"
        done
    }
    
    function tcp_status() {
        # awk [$6]++ 会把第六列的值作为key, 个数作为value, 遇到一个就+1, 然后++遍历完所有的
        summary=(netstat -tanp |awk '{status[$6]++}END{for(i in status)printf i":"status[i]" "}')
        echo "TCP连接状态 - $summary"
    }
    
    # 调用函数
    cpu
    memory
    disk
    tcp_status
    
    

    重点

    awk
    awk 的处理和数据库比较类似
        列   $2 第二列
        行   NR==2  第二行
    # 打印文件第二行第二列
    cat users.txt | awk '{if (NR==2) print  $2}'
    

    找出占用CPU/内存过高的进程

    ps
    
        -O format
            Like -o, but preloaded with some default columns.  Identical to -o                       pid,format,state,tname,time,command or -o pid,format,tname,time,cmd, see -o below.
       -e 
                  
    
    user 用户名
    uid 用户号
    pid 进程号
    ppid 父进程号
    size 内存大小, Kbytes字节.
    vsize 总虚拟内存大小, bytes字节(包含code+data+stack)
    share 总共享页数
    nice 进程优先级(缺省为0, 最大为-20)
    priority(pri) 内核调度优先级
    pmem 进程分享的物理内存数的百分比
    trs 程序执行代码驻留大小
    rss 进程使用的总物理内存数, Kbytes字节
    time 进程执行起到现在总的CPU暂用时间
    stat 进程状态
    cmd(args) 执行命令的简单格式
    
    
    #!/bin/bash
    echo "---------------- cpu top 10 ----------------------"
    ps -eo user,pid,pcpu,pmem,args --sort=-pcpu  |head -n 10
    echo "---------------- memory top 10 -------------------"
    ps -eo user,pid,pcpu,pmem,args --sort=-pmem  |head -n 10
    
    

    查看网卡实时流量

    查看网卡有2个地方 , 可以看到从开机到现在收到和发出的流量

    ifconfig

    cat /proc/net/dev

    ➜  cat /proc/net/dev
    Inter-|   Receive                                                |  Transmit
     face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
      eth0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
      eth1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
    
    #!/bin/bash
    # 网卡名通过位置传参, 因为每个机器网卡名可能不同
    NIC=$1
    echo -e " In ------ Out"
    while true; do
        # $0~ 一整行 包含网卡名 $NIC, 下面还有一直用写法, 上面用过
        OLD_IN=$(awk '$0~"'$NIC'"{print $2}' /proc/net/dev)
        # OLD_IN=$(cat /proc/net/dev | awk '/$NIC/{print $2}')
        OLD_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
        sleep 1
        NEW_IN=$(awk  '$0~"'$NIC'"{print $2}' /proc/net/dev)
        NEW_OUT=$(awk '$0~"'$NIC'"{print $10}' /proc/net/dev)
        # 开始计算和前一秒的差值
        # "%.1f%s"  保留一个小数点, %s 是后面的值
        # (( ))  双括号是计算
        IN=$(printf "%.1f%s" "$((($NEW_IN-$OLD_IN)/1024))" "KB/s")
        OUT=$(printf "%.1f%s" "$((($NEW_OUT-$OLD_OUT)/1024))" "KB/s")
        echo "$IN $OUT"
        sleep 1
    done
    
    
    

    监控批量服务器磁盘利用率

    前置知识

    1.批量就需要免密登录
    
    # 1. 密钥
    ssh-keygen -t rsa
    
    # this user must have sudo permission
    ssh-copy-id -i ~/.ssh/id_rsa.pub username@192.168.91.135 
    
    # 2.another way: 2 steps
    $ scp ~/.ssh/id_rsa.pub root@<remote_ip>:pub_key //将文件拷贝至远程服务器
    $ cat ~/pub_key >>~/.ssh/authorized_keys //将内容追加到authorized_keys文件中, 不过要登录远程服务器来执行这条命令
    
    3.将本地id_rsa.pub文件的内容拷贝至远程服务器的~/.ssh/authorized_keys文件中
    
    然后 就可以免密码登录了
    ssh -i .ssh/id_rsa username@192.168.91.135 
    
    2.expec 免交互输入密码
    # ssh 后面接命令就可以直接拿到执行返回结果
    ssh username@192.168.91.135 'df -h'
    
    #!/bin/bash
    HOST_INFO=host.info
    # ^[^#] 去掉#开头的
    for IP in $(awk '/^[^#]/{print $1}' $HOST_INFO); do
        USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO)
        PORT=$(awk -v ip=$IP 'ip==$1{print $3}' $HOST_INFO)
        TMP_FILE=/tmp/disk.tmp
        ssh -p $PORT $USER@$IP 'df -h' > $TMP_FILE
        # int() 取整,去掉20% 中的%
        USE_RATE_LIST=$(awk 'BEGIN{OFS="="}/^\/dev/{print $NF,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
    
    
    

    expect

    #!/bin/bash
    # 这里用 $* 因为要把bash 1.sh df -h sh后面的命令df -h作为一个整体
    COMMAND=$*
    HOST_INFO=host.info
    for IP in $(awk '/^[^#]/{print $1}' $HOST_INFO); do
        USER=$(awk -v ip=$IP 'ip==$1{print $2}' $HOST_INFO)
        PORT=$(awk -v ip=$IP 'ip==$1{print $3}' $HOST_INFO)
        PASS=$(awk -v ip=$IP 'ip==$1{print $4}' $HOST_INFO)
        expect -c "
           spawn ssh -p $PORT $USER@$IP
           expect {
           # \r 换行
              \"(yes/no)\" {send \"yes\r\"; exp_continue}
              \"password:\" {send \"$PASS\r\"; exp_continue}
              \"$USER@*\" {send \"$COMMAND\r exit\r\"; exp_continue}
           }
        "
        echo "-------------------"
    done
    
    也可以通过
    #!/bin/bash
    
    USERS_FILE=host.info
    
    # 循环读文件
    while read line
    do
    HOST=`echo $line | cut -f1 -d ' '`
    USER=`echo $line | cut -f2 -d ' '`
    PORT=`echo $line | cut -f3 -d ' '`
    
    echo "$HOST, $USER, $PORT"
    done <$USERS_FILE
    

    或者可以通过ansible 批量管理

    检测网站运行正常

    #!/bin/bash  
    URL_LIST="www.baidu.com www.jd.com"
    for URL in $URL_LIST; do
        FAIL_COUNT=0
        for ((i=1;i<=3;i++)); do
            # curl -o  output FILE
            #      -s silent 不输出任何内容
            #      -w 输出指定格式的内容到标准输出
            HTTP_CODE=$(curl -o /dev/null --connect-timeout 3 -s -w "%{http_code}" $URL)
            if [ $HTTP_CODE -eq 200 ]; then
                echo "$URL OK"
                break
            else
                echo "$URL retry $FAIL_COUNT"
                # FAIL_COUNT 加一
                let FAIL_COUNT++
            fi
        done
        if [ $FAIL_COUNT -eq 3 ]; then
            echo "Warning: $URL Access failure!"
        fi
    done
    
    

    目录文件变化和同步

    一些病毒(挖矿)会入侵系统后, 新建上传文件, 执行脚本

    /usr/bin

    /wwwroot 串改, 注入

    #!/bin/bash
    
    # 需要先装工具 yum install inotify-tools -y
    # 这个工具可以监控目录下文件的增删改
    # -mrq 持续监听, 递归形式, 减少冗余信息输出
    # -e 监听的事件, 增删改查等
    MON_DIR=/opt
    inotifywait -mqr --format %f -e create $MON_DIR |\
    while read files; do
        # rsync 可以将2个目录同步
       rsync -avz /opt /tmp/opt
       #echo "$(date +'%F %T') create $files" | mail -s "dir monitor" xxx@163.com
    done
    

    后台运行

    nohub bash monitor.sh &>/dev/null &

    mysql 备份

    备份库

    mysqldump -hxxx -uroot -pxxx -B DB_name > DB.sql

    备份表

    mysqldump -hxxx -uroot -pxxx DB_name table_name > table.sql

    #!/bin/bash
    # 时间格式
    DATE=$(date +%F_%H-%M-%S)
    HOST=localhost
    # 备份就用一个最小权限的用户 只能查看要备份的那部分, 只读
    USER=backup
    PASS=123.com
    BACKUP_DIR=/data/db_backup
    # egrep -v 过滤掉包含这些资源的行
    DB_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "show databases;" 2>/dev/null |egrep -v "Database|information_schema|mysql|performance_schema|sys")
    
    # 分库备份
    for DB in $DB_LIST; do
        BACKUP_NAME=$BACKUP_DIR/${DB}_${DATE}.sql
        # -B 指定库
        if ! mysqldump -h$HOST -u$USER -p$PASS -B $DB > $BACKUP_NAME 2>/dev/null; then
            echo "$BACKUP_NAME 备份失败!"
        fi
    done
    
    
    # 分表备份
    for DB in $DB_LIST; do
        BACKUP_DB_DIR=$BACKUP_DIR/${DB}_${DATE}
        [ ! -d $BACKUP_DB_DIR ] && mkdir -p $BACKUP_DB_DIR &>/dev/null
        TABLE_LIST=$(mysql -h$HOST -u$USER -p$PASS -s -e "use $DB;show tables;" 2>/dev/null)
        for TABLE in $TABLE_LIST; do
            BACKUP_NAME=$BACKUP_DB_DIR/${TABLE}.sql 
            if ! mysqldump -h$HOST -u$USER -p$PASS $DB $TABLE > $BACKUP_NAME 2>/dev/null; then
                echo "$BACKUP_NAME 备份失败!"
            fi
        done
    done
    

    监控MySQL 主从同步状态

    mysql -h$HOST -u$USER -p$PASSWD -e 'show slave status\G' 2>/dev/null |awk '/Slave_.*_Running:/{print $1$2}'
    
    Slave_IO_Running: Connecting
    Slave_SQL_Running: Yes
    
    #!/bin/bash  
    HOST=localhost
    USER=root
    PASSWD=123.com
    IO_SQL_STATUS=$(mysql -h$HOST -u$USER -p$PASSWD -e 'show slave status\G' 2>/dev/null |awk '/Slave_.*_Running:/{print $1$2}')
    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!" |mail -s "Master-Slave Staus" xxx@163.com
        fi
    done
    

    Nginx 访问日志分析

    #!/bin/bash
    # 日志格式: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"
    LOG_FILE=$1
    echo "统计访问最多的10个IP"
    # awk $1 第一个字段ip, 做count 统计, 然后排序
    # sort -k2 按照第二列排序
    awk '{a[$1]++}END{print "UV:",length(a);for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr |head -10
    echo "----------------------"
    
    echo "统计时间段访问最多的IP"
    # awk 中可以直接对时间进行比较,分析某个时间段的日志
    awk '$4>="[01/Dec/2018:13:20:25" && $4<="[27/Nov/2018:16:20:49"{a[$1]++}END{for(v in a)print v,a[v]}' $LOG_FILE |sort -k2 -nr|head -10
    echo "----------------------"
    
    echo "统计访问最多的10个页面"
    # length(a) 去重后列表内元素个数
    awk '{a[$7]++}END{print "PV:",length(a);for(v in a){if(a[v]>10)print v,a[v]}}' $LOG_FILE |sort -k2 -nr
    echo "----------------------"
    
    echo "统计访问页面状态码数量"
    awk '{a[$7" "$9]++}END{for(v in a){if(a[v]>5)print v,a[v]}}' $LOG_FILE |sort -k3 -nr
    

    自动屏蔽高访问IP

    这里是监控nginx 访问日志

    #!/bin/bash
    DATE=$(date +%d/%b/%Y:%H:%M)
    LOG_FILE=/usr/local/nginx/logs/demo2.access.log
    # 访问最后5000 条日志, 过滤ip出现10次以上的
    ABNORMAL_IP=$(tail -n5000 $LOG_FILE |grep $DATE |awk '{a[$1]++}END{for(i in a)if(a[i]>100)print i}')
    for IP in $ABNORMAL_IP; do
        if [ $(iptables -vnL |grep -c "$IP") -eq 0 ]; then
            # 通过iptables 
            iptables -I INPUT -s $IP -j DROP
            echo "$(date +'%F_%T') $IP" >> /tmp/drop_ip.log
        fi
    done
    
    

    同样 ssh 防暴力破解 也可以通过这种方式来屏蔽

    /var/log/audit/audit.log 是系统审计日志, 可以通过这个日志来统计

    LNMP环境搭建

    #!/bin/bash
    NGINX_V=1.15.6
    PHP_V=5.6.36
    TMP_DIR=/tmp
    
    INSTALL_DIR=/usr/local
    
    PWD_C=$PWD
    
    echo
    echo -e "\tMenu\n"
    echo -e "1. Install Nginx"
    echo -e "2. Install PHP"
    echo -e "3. Install MySQL"
    echo -e "4. Deploy LNMP"
    echo -e "9. Quit"
    
    function command_status_check() {
        if [ $? -ne 0 ]; then
            echo $1
            exit
        fi 
    }
    
    function install_nginx() {
        cd $TMP_DIR
        # openssl-devel https
        # pcre-devel nginx 正则支持
        yum install -y gcc gcc-c++ make openssl-devel pcre-devel wget
        wget http://nginx.org/download/nginx-${NGINX_V}.tar.gz
        tar zxf nginx-${NGINX_V}.tar.gz
        cd nginx-${NGINX_V}
        ./configure --prefix=$INSTALL_DIR/nginx \
        --with-http_ssl_module \
        --with-http_stub_status_module \
        --with-stream
        # $1 相当于传参
        command_status_check "Nginx - 平台环境检查失败!"
        make -j 4 
        command_status_check "Nginx - 编译失败!"
        make install
        command_status_check "Nginx - 安装失败!"
        mkdir -p $INSTALL_DIR/nginx/conf/vhost
        alias cp=cp ; cp -rf $PWD_C/nginx.conf $INSTALL_DIR/nginx/conf
        rm -rf $INSTALL_DIR/nginx/html/*
        echo "ok" > $INSTALL_DIR/nginx/html/status.html
        echo '<?php echo "ok"?>' > $INSTALL_DIR/nginx/html/status.php
        $INSTALL_DIR/nginx/sbin/nginx
        command_status_check "Nginx - 启动失败!"
    }
    
    function install_php() {
        cd $TMP_DIR
        yum install -y gcc gcc-c++ make gd-devel libxml2-devel \
            libcurl-devel libjpeg-devel libpng-devel openssl-devel \
            libmcrypt-devel libxslt-devel libtidy-devel
        wget http://docs.php.net/distributions/php-${PHP_V}.tar.gz
        tar zxf php-${PHP_V}.tar.gz
        cd php-${PHP_V}
        ./configure --prefix=$INSTALL_DIR/php \
        --with-config-file-path=$INSTALL_DIR/php/etc \
        --enable-fpm --enable-opcache \
        --with-mysql --with-mysqli --with-pdo-mysql \
        --with-openssl --with-zlib --with-curl --with-gd \
        --with-jpeg-dir --with-png-dir --with-freetype-dir \
        --enable-mbstring --enable-hash
        command_status_check "PHP - 平台环境检查失败!"
        make -j 4 
        command_status_check "PHP - 编译失败!"
        make install
        command_status_check "PHP - 安装失败!"
        cp php.ini-production $INSTALL_DIR/php/etc/php.ini
        cp sapi/fpm/php-fpm.conf $INSTALL_DIR/php/etc/php-fpm.conf
        cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
        chmod +x /etc/init.d/php-fpm
        /etc/init.d/php-fpm start
        command_status_check "PHP - 启动失败!"
    }
    
    read -p "请输入编号:" number
    case $number in
        1)
            install_nginx;;
        2)
            install_php;;
        3)
            install_mysql;;
        4)
            install_nginx
            install_php
            ;;
        9)
            exit;;
    esac
    

    bash -x test.sh 可以查看shell的执行过程

    #/bin/bash
    echo $0(代表命令本身);
    echo $1; (代表第几个参数)
    echo $2;
     
    [root@LocalWeb01 ~]# ./1.sh 2 3
    ./1.sh
    2
    3
    
    $#代表参数个数 
    $* 代表命令行的 所有参数代表一个整体
    $@ 代表命令行的 所有参数代表一个整体,不过把每个参数区分对待
     
    $? 上条命令执行是否成功 0是成功
    $$ 当前运行的进程号
    $! 后台运行的最后一条的进程号
    

    python 调用shell 命令

    import subprocess
    return_code, res = subprocess.getstatusoutput('pwd')
    print(return_code, res)
    

    遇到比较复杂的shell 脚本, 也可以用python 处理源文件

    然后生成shell 脚本, 执行脚本

    或者直接调用shell 命令

    相关文章

      网友评论

          本文标题:shell 最使用实战整理

          本文链接:https://www.haomeiwen.com/subject/fefbsltx.html