几个例子掌握shell脚本
程序员文章站
2022-05-29 23:23:33
...
传说一个俄罗斯程序员写了一堆脚本,会给老婆发加班短信、会在宿醉不醒时给自己请假、会自动根据邮件恢复客户的数据库、还可以一键远程煮咖啡,好神奇的样子(虽然我到现在也不知道哪里能买到能联网的咖啡机)。
程序最大的意义就是代替人们做重复的工作。
在我们日常的运维工作中,常常敲一些重复的命令,比如我们在调试程序时,每次都要重启应用,每次都要敲一堆重复命令,敲一次两次还可以,但是当到敲十几次、几十次就要抓狂了,这个时候一个脚本就很有必要了。再比如我们在服务器上部署一个java程序,由于内存溢出或内存泄漏等原因程序可能挂掉,所以我们就需要一个检查进程的脚本了,并且通过定时任务实现进程监控。
下面我将列几个我之前写过的脚本:
- 应用启停脚本
#!/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进程,简直是痛苦的一匹。该脚本支持菜单和参数两种方式使用,涉及常见的进程操作、菜单的实现、参数的实现,大家可以在写脚本时用作参考。
- 应用部署以及启停脚本
#!/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等知识,可用作参考。
- 应用巡检以及启停脚本
#! /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)、记录日志、发送邮件、端口和进程的检测,可作为参考。
- 应用部署脚本
#!/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)脚本重启应用。
下一篇: PHP项目开发中最常用的自定义函数整理