什么是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

什么是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 &

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

脚本简单解析

# 声明脚本,加#标识注释
#!/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

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

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

关于[] 和[[]]

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

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

关于管道符的解释

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

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

其中,$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

11-08 06:41