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脚本支持的一些语言特性,完成想要的功能。
总结下,对于我们经常用的在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