几个例子掌握shell脚本

    传说一个俄罗斯程序员写了一堆脚本,会给老婆发加班短信、会在宿醉不醒时给自己请假、会自动根据邮件恢复客户的数据库、还可以一键远程煮咖啡,好神奇的样子(虽然我到现在也不知道哪里能买到能联网的咖啡机)。

    程序最大的意义就是代替人们做重复的工作。

    在我们日常的运维工作中,常常敲一些重复的命令,比如我们在调试程序时,每次都要重启应用,每次都要敲一堆重复命令,敲一次两次还可以,但是当到敲十几次、几十次就要抓狂了,这个时候一个脚本就很有必要了。再比如我们在服务器上部署一个java程序,由于内存溢出或内存泄漏等原因程序可能挂掉,所以我们就需要一个检查进程的脚本了,并且通过定时任务实现进程监控。

    下面我将列几个我之前写过的脚本:

  1. 应用启停脚本
    #!/bin/bash
    
    stopuwsgi()
    {
        echo "关闭uwsgi..."
        for pid in `ps -aux|grep uwsgi|grep ini|grep -v grep|awk '{print $2}'` ; do
            kill -9 ${pid}
        done
        sleep 3
        echo "已关闭!"
    }
    startuwsgi()
    {
        if [ `ps -aux|grep uwsgi|grep ini|grep -v grep|wc -l` -ne 0 ]; then
            echo 'ERR!进程已存在,未开启!'
            return
        fi
        echo '开启uwsgi...'
        cd /app/ds_website
        uwsgi --ini uwsgi.ini
        sleep 3
        echo "uwsgi进程数:`ps -aux|grep uwsgi|grep ini|grep -v grep|wc -l`"
        echo '已开启!'
    }
    restartuwsgi()
    {
        stopuwsgi
        startuwsgi
        echo '已重启!'
    }
    
    menu()
    {
        while [ "1" ]
        do
            clear
            echo "功能菜单:"
            echo "1、重启uwsgi"
            echo "2、启动uwsgi"
            echo "3、停止uwsgi"
            echo "0、退出"
            echo "select==>>"
            tput cup 5 10
            read choice
            case ${choice} in
            0) break;;
            1) echo "重启uwsgi(y/n)"
                read key
                if [ ${key} = 'y' -o ${key} = 'Y' ]; then
                    restartuwsgi
                fi
                echo '按任意键继续...'
                read key
                continue;;
            2) echo "启动uwsgi(y/n)"
                read key
                if [ ${key} = 'y' -o ${key} = 'Y' ]; then
                    startuwsgi
                fi
                echo '按任意键继续...'
                read key
                continue;;
            3) echo "停止uwsgi(y/n)"
                read key
                if [ ${key} = 'y' -o ${key} = 'Y' ]; then
                    stopuwsgi
                fi
                echo '按任意键继续...'
                read key
                continue;;
            esac
        done
    }
    
    if [ $1 = 'start' ]; then
        startuwsgi
    elif [ $1 = 'restart' ]; then
        restartuwsgi
    elif [ $1 = 'stop' ]; then
        stopuwsgi
    else
        menu
    fi
    
     说明:该脚本用于启停python Django 程序容器:uwsgi,由于uwsgi启动后会开启8个进程,如果手动重启需要ps找出所有进程的pid,然后逐个kill掉,然后再开启uwsgi,在调试程序时经常要启停应用,如果每次都逐一kill进程,简直是痛苦的一匹。

    该脚本支持菜单和参数两种方式使用,涉及常见的进程操作、菜单的实现、参数的实现,大家可以在写脚本时用作参考。

  2. 应用部署以及启停脚本
    #!/bin/bash
    
    setup(){
    	echo "部署spider"
    	cd /app
    	echo "删除原代码..."
    	rm -rf spider
    	echo "当前工作目录:`pwd`"
    	echo "开始clone项目..."
    	git clone https://gitee.com/dushen666/spider.git
    	cd spider
    	echo "当前工作目录:`pwd`"
    	echo "修改配置文件..."
    	sed -i "s/self.conn = MySQLdb.connect.*/self.conn = MySQLdb.connect(host='localhost', port=3306, user='root', passwd='pawd123--', db='movie-website1', charset='utf8')/" /app/spider/spider/pipelines.py
    	echo '应用部署完毕!'
    }
    
    startup(){
    	echo "开启spider"
    	cd ~/spider
    	nohup python /app/spider/quickstart.py &
    	echo "spider已开启,5秒后打开日志"
    	sleep 5
    	tail -f /app/spider/nohup.out
    }
    
    sstop(){
    	echo "结束spider"
    	if [ `ps -aux|grep python|grep quickstart|grep -v grep|wc -l` -eq '0' ]; then
    		echo "spider进程不存在,无需停止!"
    		return
    	fi
    	for pid in `ps -aux|grep python|grep quickstart|grep -v grep|awk '{print $2}'`;do
    		kill -9 $pid
    		echo "已杀死进程$pid"
    	done
    	if [ `ps -aux|grep tomcat|grep -v grep|wc -l` -eq '0' ]; then
    		echo "OK!成功停止服务!"
    		return
    	fi
    	echo "ERR!停止服务异常,需手动停止!"
    }
    
    ttest(){
    	if [ `ps -aux|grep python|grep quickstart|grep -v grep|wc -l` -eq '0' ]; then
    		echo "spider进程不存在,自动开启!"
    		cd ~/spider
    		nohup python /app/spider/quickstart.py &
    		echo "已开启spider"
    	fi
    }
    
    case $1 in
    	'setup' ) 
    		setup;;
    	'start' )
    		startup;;
    	'stop' )
    		sstop;;
    	'test' )
    		ttest;;
    	* )
    		echo "Usage:`basename $0` [options] filename";;
    esac
    
    
     说明:如何将开发好的代码快速部署到服务器上,最常见的部署代码方式就是将程序编译好的增量包FTP放到服务器上,然后解压覆盖,再重启服务。本脚本利用github实现了程序的快速部署,大致流程是这样:删掉服务器上原有的代码->使用git clone将github上的代码克隆到本地->修改配置文件->重启服务。本脚本只适合使用github或码云管理的项目,在想要发布程序时,只需要执行一下脚本,所有的事情就自动做了。

    该脚本涉及sed修改配置文件、git clone等知识,可用作参考。

  3. 应用巡检以及启停脚本
    #! /bin/bash
    
    ##################################################################
    ##			作者:	杜神				##
    ##			日期:	2018-01-19			##
    ##			功能:	DS管理工具集			##
    ##			version:	1.0			##
    ##################################################################
    
    
    APP_PORT1=8080
    APP_PORT2=8443
    REDIS_PORT1=6666
    REDIS_PASSWD='pawd123--'
    LOG_NAME=`date +%Y%m%d`.log
    LOG_PATH=/app/logs/script/
    TOMCAT_HOME=~/environment/tomcat8
    MAILS=/app/conf/mail.lst
    FLAG=/app/conf/err
    
    set -i
    source ~/.bashrc
    #应用服务状态检测
    app_check()
    {
    	echo "应用服务状态检测……"|tee -a $LOG_PATH$LOG_NAME
    	state='0' #0正常	1异常
    	if [ `ps -aux|grep tomcat|grep -v grep|wc -l` -eq '1' ]; then
    		echo "tomcat进程正常"|tee -a $LOG_PATH$LOG_NAME
    	else
    		echo "tomcat进程异常"|tee -a $LOG_PATH$LOG_NAME
    		state='1'
    	fi
    	
    	if [ `netstat -an|grep 0.0.0.0:$APP_PORT1|grep LISTEN|wc -l` -eq '1' ]; then
    		echo "端口$APP_PORT1状态正常"|tee -a $LOG_PATH$LOG_NAME
    	else
    		echo "端口$APP_PORT1异常"|tee -a $LOG_PATH$LOG_NAME
    		state='1'
    	fi
    
    	if [ `netstat -an|grep 0.0.0.0:$APP_PORT2|grep LISTEN|wc -l` -eq '1' ]; then
    		echo "端口$APP_PORT2状态正常"|tee -a $LOG_PATH$LOG_NAME
    	else
    		echo "端口$APP_PORT2异常"|tee -a $LOG_PATH$LOG_NAME
    		state='1'
    	fi
    	
    	if [ $state -eq '0' ]; then
    		echo "OK!应用服务状态检测正常"|tee -a $LOG_PATH$LOG_NAME
    	else
    		echo "ERR!应用服务状态存在异常"|tee -a $LOG_PATH$LOG_NAME
    	fi
    	
    	return $state
    }
    
    #环境检查
    environment_check()
    {
    	echo "环境检查……"|tee -a $LOG_PATH$LOG_NAME
    	state='0' #0正常	1异常
    	echo "检查redis状态……"|tee -a $LOG_PATH$LOG_NAME
    	echo "1. redis进程"|tee -a $LOG_PATH$LOG_NAME
    	if [ `ps -aux|grep redis|grep -v grep|wc -l` -ne '0' ]; then
    		echo "redis进程存在`ps -aux|grep redis|grep -v grep|wc -l`个:"|tee -a $LOG_PATH$LOG_NAME
    		echo `ps -aux|grep redis|grep -v grep`|tee -a $LOG_PATH$LOG_NAME
    	else 
    		echo "redis进程异常"|tee -a $LOG_PATH$LOG_NAME
    		state='1'
    	fi
    	echo "2. redis端口"|tee -a $LOG_PATH$LOG_NAME
    	if [ `netstat -an| grep $REDIS_PORT1|grep LISTEN|wc -l` -ne '0' ]; then
    		echo "redis端口存在`netstat -an| grep $REDIS_PORT1|grep LISTEN|wc -l`个:"|tee -a $LOG_PATH$LOG_NAME
    		echo `netstat -an| grep $REDIS_PORT1|grep LISTEN`|tee -a $LOG_PATH$LOG_NAME
    		echo "连接数:`netstat -an| grep $REDIS_PORT1|grep ESTABLISHED|wc -l`"|tee -a $LOG_PATH$LOG_NAME
    	else 
    		echo "redis端口异常"|tee -a $LOG_PATH$LOG_NAME
    		state='1'
    	fi
    	echo "3. redis测试"|tee -a $LOG_PATH$LOG_NAME
    	
    	if [ `/servers/redis-2.8.19/src/redis-cli  -p $REDIS_PORT1 -a $REDIS_PASSWD "ping"` = "PONG" ]; then
    		echo "redis测试正常"|tee -a $LOG_PATH$LOG_NAME
    	else
    		echo "redis测试异常"|tee -a $LOG_PATH$LOG_NAME
    		state='1'
    	fi
     
    	echo "java版本:"|tee -a $LOG_PATH$LOG_NAME
    	echo "`java -version`"|tee -a $LOG_PATH$LOG_NAME
    	echo "tomcat版本:"|tee -a $LOG_PATH$LOG_NAME
    	echo "`$TOMCAT_HOME/bin/version.sh`" | grep -v "Using"|tee -a $LOG_PATH$LOG_NAME
     
    	if [ $state -eq '0' ]; then
    		echo "OK!环境检查正常"|tee -a $LOG_PATH$LOG_NAME
    	else
    		echo "ERR!环境检查存在异常"|tee -a $LOG_PATH$LOG_NAME
    	fi
    	
    	return $state
    }
    
    #健康检查
    health_check()
    {
    	echo "健康检查……"|tee -a $LOG_PATH$LOG_NAME
    	environment_check
    	a=$?
    	app_check
    	b=$?
    	if [ $a -eq "0" -a $b -eq "0" ]; then
    		echo "OK!健康检查正常"|tee -a $LOG_PATH$LOG_NAME
    		return '0'
    	fi
    	echo "ERR!健康检查存在异常"|tee -a $LOG_PATH$LOG_NAME
    	return '1'
    }
    
    #启动服务
    app_start()
    {
    	echo "启动服务……"|tee -a $LOG_PATH$LOG_NAME
    	echo "检查当前登录用户……"|tee -a $LOG_PATH$LOG_NAME
    	if [ `whoami` != "app" ]; then
    		echo "ERR!当前登录用户为'`whoami`',请使用应用管理员用户登录!"|tee -a $LOG_PATH$LOG_NAME
    		return
    	fi
    	echo "当前用户:`whoami`"|tee -a $LOG_PATH$LOG_NAME
            if [ `ps -aux|grep tomcat|grep -v grep|wc -l` -ne '0' ]; then
                    echo "ERR!tomcat进程已存在,未启动服务!"|tee -a $LOG_PATH$LOG_NAME
    	return
            fi 
    	environment_check
    	a=$?
    	if [ $a -eq '1' ]; then
    		echo "ERR!环境检查不通过,未启动服务!"|tee -a $LOG_PATH$LOG_NAME
    		return
    	fi
    	echo "打开tomcat……"|tee -a $LOG_PATH$LOG_NAME
    	echo `$TOMCAT_HOME/bin/startup.sh`|tee -a $LOG_PATH$LOG_NAME
    	echo "OK!服务已启动"|tee -a $LOG_PATH$LOG_NAME
    	echo "tomcat 启动完成,是否打开日志(y/n)?"
    	read key
    	if [ $key = "y" -o $key = "Y" ]; then
    		echo "打开日志……"|tee -a $LOG_PATH$LOG_NAME
    		tail -f $TOMCAT_HOME/logs/catalina.out
    	fi
    
    }
    
    #停止服务
    app_stop()
    {
    	echo "停止服务……"
    	if [ `ps -aux|grep tomcat|grep -v grep|wc -l` -eq '0' ]; then
    		echo "tomcat进程不存在,无需停止!"|tee -a $LOG_PATH$LOG_NAME
    		return
    	fi
    #	echo `$TOMCAT_HOME/bin/shutdown.sh`|tee -a $LOG_PATH$LOG_NAME
    #	sleep 8
    #	if [ `ps -aux|grep tomcat|grep -v grep|wc -l` -eq '0' ]; then
    #		echo "成功停止服务!"|tee -a $LOG_PATH$LOG_NAME
    #		return
    #	fi
    	for pid in `ps -aux|grep tomcat|grep -v grep|awk '{print $2}'`;do
    		kill -9 $pid
    		echo "已杀死进程$pid"|tee -a $LOG_PATH$LOG_NAME
    	done
    	if [ `ps -aux|grep tomcat|grep -v grep|wc -l` -eq '0' ]; then
    		echo "OK!成功停止服务!"|tee -a $LOG_PATH$LOG_NAME
    		return
    	fi
    	echo "ERR!停止服务异常,需手动停止!"|tee -a $LOG_PATH$LOG_NAME
    }
    
    #主菜单
    menu()  
    {       
    	while [ "1" ]
    	do      
    		clear
    		echo "功能菜单:"
    		echo "1. 健康检查"
    		echo "2. 应用服务状态检测"
    		echo "3. 环境检测"
    		echo "4. 启动服务"
    		echo "5. 停止服务"
    		echo "0. 退出"
    		echo "select==>>"
    		tput cup 7 10
    		tput cnorm 
    		read choice
    		case $choice in
    		0) clear
    			break;;
    		1) echo "开始健康检查(y/n)?"
    			read key
    			if [ $key = "y" -o $key = "Y" ]; then
    				echo "+++++++++++++++++++++++++++健康检查-time:`date '+%Y-%m-%d %H:%M:%S'`+++++++++++++++++++++++++++"|tee -a $LOG_PATH$LOG_NAME
    				health_check
    			fi
    			echo "按任意键继续……"
    			read key
    			continue;;
    		2) echo "开始应用服务状态检测(y/n)?"
    			read key
    			if [ $key = "y" -o $key = "Y" ]; then
    				echo "+++++++++++++++++++++++应用服务状态检测-time:`date '+%Y-%m-%d %H:%M:%S'`+++++++++++++++++++++++"|tee -a $LOG_PATH$LOG_NAME
    				app_check
    			fi
    			echo "按任意键继续……"
    			read key
    			continue;;
    		3) echo "开始环境检测(y/n)?"
    			read key
    			if [ $key = "y" -o $key = "Y" ]; then
    				echo "+++++++++++++++++++++++++++环境检测-time:`date '+%Y-%m-%d %H:%M:%S'`+++++++++++++++++++++++++++"|tee -a $LOG_PATH$LOG_NAME
    				environment_check
    			fi
    			echo "按任意键继续……"
    			read key
    			continue;;
    		4) echo "启动服务(y/n)?"
    			read key
    			if [ $key = "y" -o $key = "Y" ]; then
    				echo "+++++++++++++++++++++++++++启动服务-time:`date '+%Y-%m-%d %H:%M:%S'`+++++++++++++++++++++++++++"|tee -a $LOG_PATH$LOG_NAME
    				app_start
    			fi
    			echo "按任意键继续……"
    			read key
    			continue;;
    		5) echo "停止服务(y/n)?"
    			read key
    			if [ $key = "y" -o $key = "Y" ]; then
    				echo "+++++++++++++++++++++++++++停止服务-time:`date '+%Y-%m-%d %H:%M:%S'`+++++++++++++++++++++++++++"|tee -a $LOG_PATH$LOG_NAME
    				app_stop
    			fi
    			echo "按任意键继续……"
    			read key
    			continue;;
    		esac    
    	done    
    }       
    
    while getopts 'dm' opt;
    do
    	case $opt in
    		d ) 
    			echo "日常周期巡检------>>>>-time:`date '+%Y-%m-%d %H:%M:%S'`"|tee -a $LOG_PATH$LOG_NAME
    			health_check >/app/tmp/daily.log
    			k=$?
    			if [ $k -eq '1' -a ! -f $FLAG ]; then
    				touch $FLAG
    				echo -e '\n\n\n' >> /app/tmp/daily.log
    				ps -aux|awk '{if($3>20) print $1,$2,$3,$4,$9,$10,$11}' >> /app/tmp/daily.log
    				echo -e '\n\n\n' >> /app/tmp/daily.log
    				tail -n 20 $TOMCAT_HOME/logs/catalina.out >> /app/tmp/daily.log
    				for mail in `cat $MAILS` ;do
    					mail -s "DS服务器周期巡检报告 `date '+%Y-%m-%d %H:%M:%S'`" "$mail" < /app/tmp/daily.log
    					echo "已发送通知邮件:$mail"|tee -a $LOG_PATH$LOG_NAME
    				done
    				app_start
    			fi
    			echo "OK!日常周期巡检完成------>>>>-time:`date '+%Y-%m-%d %H:%M:%S'`"|tee -a $LOG_PATH$LOG_NAME;;
    		m )
    			menu;;
    		* )
    			echo "Usage:`basename $0` [options] filename";;
    	esac
    done
    
    
     说明:该脚本是我为一个java程序写的综合脚本。包含应用的启停,配置crontab定时任务后可实现进程、端口等的巡检,并实现邮件告警并生成巡检日志。

    该脚本涉及options的实现(类似:ps -ef中的-ef)、记录日志、发送邮件、端口和进程的检测,可作为参考。

  4. 应用部署脚本
    #!/bin/sh
    
    
    cd /app
    echo "删除原代码..."
    rm -rf ds_website
    echo "当前工作目录:`pwd`"
    rm -rf Video-website
    echo "开始clone项目..."
    git clone https://gitee.com/dushen666/Video-website.git
    echo "拷贝覆盖项目..."
    cp -Rf Video-website ds_website
    cd ds_website
    echo "当前工作目录:`pwd`"
    echo "修改配置文件..."
    sed -i 's/^ALLOWED_HOSTS.*/ALLOWED_HOSTS = ["111.89.11.51","www.dushen6.cn",]/g' ./ds_website/settings.py
    sed -i 's/^DEBUG.*/DEBUG = False/g' ./ds_website/settings.py
    sed -i 's/^configfile.*/configfile = "\/app\/ds_website\/conf\/global.conf"/g' ./ds_website/settings.py
    
    sed -i 's/configfile = .*/configfile = "\/app\/ds_website\/conf\/global.conf"/' ./website1/cloudfiles/downloader.py
    
    sed -i 's/^PASSWORD.*/PASSWORD:pawd123--/g' ./conf/global.conf
    sed -i 's/^NAME.*/NAME:movie-website1/g' ./conf/global.conf
    
    echo "修改表结构..."
    python manage.py migrate   # 创建表结构
    
    sh /app/sbin/website1.sh restart
    
    echo '应用部署完毕!'
     说明:该脚本与(2)类似,同样是使用git clone克隆脚本到本地,使用sed修改配置文件,之后使用了Django自带的manage.py修改了表结构,最后调用了(1)脚本重启应用。

猜你喜欢

转载自dushen.iteye.com/blog/2422603