• Shell脚本基础


    什么是Shell

    Shell是一个命令解释器,它通过接受用户输入的Shell命令来启动、暂停、停止程序的运行或对计算机进行控制。Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。Shell 本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序。

    [root@localhost bin]# echo $SHELL
    /bin/bash
    [root@localhost bin]# cat /etc/shells
    /bin/sh
    /bin/bash
    /usr/bin/sh
    /usr/bin/bash
    /bin/tcsh
    /bin/csh
    # 查看自己系统的Shell解析器 Centos 默认的解析器是 bash
    [root@localhost bin]# echo $SHELL
    /bin/bash
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    什么是Shell脚本

    shell脚本就是由Shell命令组成的执行文件,将一些命令整合到一个文件中,进行处理业务逻辑,脚本不用编译即可运行。它通过解释器解释运行,所以速度相对来说比较慢。
    Shell脚本中最重要的就是对Shell命令的使用与组合,再使用Shell脚本支持的一些语言特性,完成想要的功能。

    用脚本启动和停止项目的优势

    • 简化操作:通过编写Shell脚本,可以将启动和停止程序的步骤整合到一个脚本中,简化了手动执行多个命令的过程。只需要运行一个脚本即可完成启动或停止操作。
    • 自动化管理:使用Shell脚本可以实现程序的自动化管理。可以将启动和停止脚本与其他任务或系统事件结合,实现定时启动或停止程序的功能,提高了系统的可靠性和稳定性。
    • 统一管理:通过使用Shell脚本,可以将程序的启动和停止操作集中管理,避免了手动操作可能带来的错误和遗漏。所有相关的启动和停止步骤都在脚本中定义,更加方便维护和更新。
    • 可扩展性:使用Shell脚本能够为启动和停止操作提供更大的灵活性和扩展性。你可以根据需要添加其他额外的操作,如检查程序是否已经在运行、备份数据、发送通知等。
    • 文档化和传承:编写Shell脚本可以作为记录和传承的工具。通过脚本,你可以清晰地记录下程序的启动和停止步骤,并将其分享给其他人使用或维护。

    总结下,对于我们经常用的在linux上启动项目大概分为以下步骤

    # 查看相应的java进程
    ps -ef|grep java
    # 找到对应的PID,杀死进程 或者直接kill -9 PID
    kill -15 PID 
    # 后台启动对应的java服务,指定堆栈大小,指定日志文件位置等
    nohup java -server -Xms256m -Xmx512m -XX:MaxNewSize=1024m -XX:MaxPermSize=1024m -jar jar包名字 > ${logdir}/${logname}.txt 2>&1 &
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    尤其是启动命令,每个人都可能不一样,所以将上述命令写入脚本里面,进行统一运行管理是非常有必要的

    脚本简单解析

    # 声明脚本,加#标识注释
    #!/bin/bash
    # $0表示脚本文件名 $1 #获取脚本执行后的第一个参数  #获取第二个参数 
    # 例如./startup.sh start filename.jar 第一个参数是start 第二个参数是filename.jar
    INPUT=$2 
    # 利用readlink获得绝对路径,其中-f 选项可以递归跟随给出文件名
    FILE_PATH=`readlink -f ${INPUT}`
    # 获取文件名及后缀(filename.jar),去掉文件最后一个/及其左边的字符串
    SERVICE=${INPUT##*/}
    # 获取文件名(filename),去掉最后一个.极其右边的字符串
    SERVICE_NAME=${SERVICE%.*}
    # 指定发布路径为当前路径
    DEPLOY_DIR=`pwd`
    # 分配堆内存-server:一定要作为第一个参数,在多个CPU时性能佳 -Xms:Heap初始值 -Xmx:java heap最大值,使用的最大内存
    # -XX:PermSize: JVM初始分配的非堆内存 -XX:MaxPermSize:设定最大内存的永久保存区域
    #JVM_OPTS="-server -Xms256m -Xmx512m -XX:MaxNewSize=1024m -XX:MaxPermSize=1024m"
    JVM_OPTS="-server -Xms256m -Xmx512m"
    # 如果第一个参数为空 echo将会在命令行上显示: 未输入操作名...,然后退出执行脚本
    if [[ "$1" = "" ]];
    then
        echo -e "\033[0;31m 未输入操作名 \033[0m  \033[0;34m {start|stop|restart|status} \033[0m"
        exit 1
    fi
     
    if [[ "$SERVICE" = "" ]];
    then
        echo -e "\033[0;31m 未输入应用名 \033[0m"
        exit 1
    fi
     
    LOGS_DIR="$DEPLOY_DIR/logs/$SERVICE_NAME"
    echo "$LOGS_DIR"
    #  $后面加变量表示引用这个变量的值,判断日志目录是否为目录,不为目录则创建文件
    if [[ ! -d "$LOGS_DIR" ]]; then
            mkdir -p ${LOGS_DIR}
    fi
     
    LOG_PATH="$LOGS_DIR/stdout.out"
    pid=0
    # 开始运行
    start()
    {   # 調用检查PID方法
    	checkPid
        如果
        # 如果PID不为0返回false,用!取反,则为true
    	if [[ ! -n "$pid" ]]; then
        # 启动java 服务 dontKillMe随便写哦,写这个只是为了看起来直观目的是告诉jenkins执行完后,不要把该子进程杀掉
        #因为jenkins根据BUILD_ID自动关闭shell运行期间产生的进程,修改变量值,值的内容自定义,防止nohup被关闭
        BUILD_ID=dontKillMe  nohup java ${JVM_OPTS} -jar  ${FILE_PATH} >> ${LOG_PATH} 2>&1 &
        echo "$SERVICE_NAME is starting you can check the $LOG_PATH"
      else
          echo "$SERVICE_NAME is runing PID: $pid"
      fi
    }
     # 检查PID是否唯一
    checkPid()
    {
        # 指令解释:ps:显示进程 -e:显示所有进程-f:全格式 grep:查找字符串 grep -v -grep:过滤自己执行的grep awk:提取主要列 
        # awk '{print $2}' 就是提取上述执行结果的第二例,即我们最想要的PID
        pid=`ps -ef |grep ${FILE_PATH} |grep -v grep |awk '{print $2}'`
    }
     
    stop()
    {
    	checkPid
        # -z检测字符串长度是否为0,为0返回 true; -n检测字符串长度是否为0,不为0返回 true; str 检测字符串是否为空,不为空返回 true。
        if [[ ! -n "$pid" ]]; then
         echo "$SERVICE_NAME not runing"
        else
          echo "$SERVICE_NAME stop..."
          kill -9 ${pid}
        fi
    }
    # 重启方法,先调用停止,2秒后调用开始
    restart()
    {
    	stop
    	sleep 2
    	start
    }
    # 查看指定服务的运行状态
    status()
    {
       checkPid
       if [[ ! -n "$pid" ]]; then
         echo "$SERVICE_NAME not runing"
       else
         echo "$SERVICE_NAME runing PID: $pid"
       fi
    }
    # case语句根据输入变量,调用对应的上面方法
    case $1 in
              start) start;;
              stop)  stop;;
              restart)  restart;;
              status)  status;;
                  *)  echo "require start|stop|restart|status"  ;;
    esac
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    脚本在服务器上执行,需要增加执行权限

    # 授予可以执行的权限
    chmod +x ***.sh
    # 使用相对路径启动
    ./***.sh
    # 使用绝对路径启动 例如
    /usr/local/***.sh
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    关于[] 和[[]]

    [ -z “$pid” ] 单对中括号变量必须要加双引号

    [[ -z $pid ]] 双对括号,变量不用加双引号

    关于管道符的解释

    例如我们查询出来了jar进程的信息,此时需要获取到这条进程信息的PID就可以使用awk命令将自己需要的某一列数据单独提取出来,示例如下

    ps -ef|grep xh-1.0-SNAPSHOT.jar|grep -v grep|awk '{print $2}' 3256
    
    • 1

    其中,$2代表提取进程信息中第二列的值,而我们使用ps命令查询出的进程信息中的第二列对应的正好就是进程的PID(注意:$0表示获取整个当前行)
    可以看到,通过awk '{print $2}'命令,我们成功拿到了xh-1.0-SNAPSHOT.jar进程的PID

    管道符“|”用来隔开两个命令,管道符左边命令的输出会作为管道符右边命令的输入。

    那么这个命令行的解析如下:`ps -ef |grep java |grep -v grep |awk ‘{print $2}’

    1、ps -ef 显示所有的进程,其中后面的e是显示结果的意思,f是显示完整格式,其他比如-w是不限制列宽显示,具体可见ps --help all
    2、ps -ef|grep java作用是把包括java这个关键字的进程都显示出来
    3、ps -ef|grep java会把grep java的进程也统计进来,因此用ps -ef|grep java|grep -v grep去除grep进程
    4、最后,只包含java关键字的进程筛选结果作为输入给awk ‘{print $2}’,这个部分的作用是提取输入的第二列,而第二列正是进程的PID
    参考地址:https://blog.csdn.net/fengxing_2/article/details/119243422
    https://blog.51cto.com/activity-first-publish/index

  • 相关阅读:
    springboot使用pagehelper分页失效场景
    立即执行函数在前端国际化方案中的应用
    小学生python游戏编程arcade----可旋转的坦克
    MyBatis insert标签
    【Java基础】File类 IO流
    功率放大器低功率射频放大器导轨式0-10V转4-20mADC24V隔离变送器
    php常见的危险函数
    idea实用快捷键(持续更新...)
    【无标题】
    redis集群实战部署 - 三主三从 (亲测可用)
  • 原文地址:https://blog.csdn.net/neusoft2016/article/details/134129843