当前位置: 首页 > news >正文

使用sudo命令执行程序不保留父进程

1. 背景

程序使用Jenkins发布,启动用户是普通用户。有时会在服务器上直接重启程序,使用“sudo -u 普通用户 程序”执行时,会产生两个进程一个是"sudo -u …"的父进程,一个是“程序”的子进程。为了不混淆研发,所以修改重启脚本,执行后只保留子进程。

2. 现象

  1. 普通用户执行sleep命令
sudo -u control sleep 20
  1. 查看sleep进程
# 查看命令
ps -ef | grep sleep | grep -v grep
# 看到两个进程
root     20043 19956  0 10:42 pts/0    00:00:00 sudo -u control sleep 20
control  20044 20043  0 10:42 pts/0    00:00:00 sleep 20
  • 父进程是root执行的,进程ID=20043
  • 子进程是普通用户control执行的,父进程ID=20043

3. 解决

  1. 使用bash -c和disown解决
sudo -u control bash -c "sleep 20 & disown"
  1. 查看sleep进程
# 查看命令
ps -ef | grep sleep | grep -v grep
# 看到只有1个进程
control  20167     1  0 10:54 pts/0    00:00:00 sleep 20

4. 说明

bash -c 结合 disown 是一种在 Linux 中启动后台进程并使其与当前 shell 分离的有效方法

4.1 基本概念

  1. bash -c 命令
    bash -c “command” 允许您直接在命令行中执行一段 Bash 脚本,而不需要先创建一个脚本文件。

  2. disown 命令
    disown 是 Bash 的内置命令,用于从当前 shell 的作业表中移除作业,使它们不再接收 SIGHUP 信号(当终端关闭时发送的信号)。

4.2 工作原理

使用 bash -c “command & disown” 时:

  1. bash -c 启动一个新的 Bash 子 shell
  2. 在这个子 shell 中,command & 将命令置于后台运行
  3. disown 立即将这个后台作业从子 shell 的作业表中移除
  4. 子 shell 退出,但后台进程继续运行,其父进程变为 init (PID 1)

5. 样例

  1. 脚本目录结构
[root@centos7 kol-backend]# tree
.
├── bak
├── lib
├── script
│   └── restart.sh
└── sourcecode
  • kol-backend:程序主目录
    • bak子目录:启动成功后备份目录;
    • lib子目录: Jenkins推送压缩包目录;
    • script子目录:重启脚本目录;
    • sourcecode子目录:程序运行目录;

注意:程序主目录及子目录的属主都是程序运行的普通用户

  1. 重启脚本
cat restart.sh
#!/bin/bash
#######################################################
# 脚本用于重启程序
# 使用前需要定义程序路径和变量
# 使用前需要修改启动程序命令,例如java路径和启动的普通账号
######################################################## 定义程序路径和变量
APP_HOME="/public/application/kol-backend"
APP_NAME="kol-job.jar"
CONF_NAME="shared-config.tar.gz"
ENV_NAME="kol-prod"
# lib子目录: Jenkins推送压缩包目录; bak子目录:启动成功后备份目录; sourcecode子目录:运行程序目录; script子目录:重启脚本目录# 当前登录用户
CURRENT_USER=$(id -un)   
# 获取当前时间
CURRENT_TIME=$(date +"%Y%m%d%H%M%S")
# 当前目录下创建脚本日志目录
mkdir -p logs# 获取脚本名称
SCRIPT_FULL_NAME=$(basename "$0")
# 移除最后一个点及其后的所有字符
SCRIPT_NAME="${SCRIPT_FULL_NAME%.*}"
# 定义脚本日志文件
LOG_FILE=logs/${SCRIPT_NAME}_${CURRENT_TIME}.logDATE_TIME=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "\n $DATE_TIME: #### Begin ####" >> $LOG_FILE# 1. 使用root账号停服务
# 获取运行程序进程的PID
PID=$(sudo ps -ef | grep "$APP_HOME/sourcecode/$APP_NAME" | grep -v grep | awk '{print $2}');
# 将获取的旧进程PID结果写入日志 
[ -n "$PID" ] && echo -e "\n $APP_NAME OLD $PID">>$LOG_FILE || echo -e "\n $APP_NAME PID为空">>$LOG_FILE;
# 正常停止进程 
[ -n "$PID" ] && sudo kill $PID && echo -e "\n $APP_NAME 开始停止">>$LOG_FILE;# 2. 检查进程PID是否存在,30秒后强杀
# 连续30秒检查进程PID是否存在,PID不存在退出循环
[ -n "$PID" ] && for i in {1..30}; do sudo kill -0 $PID 1>/dev/null || break; sleep 1; done;
# 超过30秒后,仍然存在进程PID,启动强杀 
sudo kill -0 $PID 2>/dev/null && sudo kill -9 $PID >/dev/null && echo -e "\n $APP_NAME 启用强杀">>$LOG_FILE
sudo sleep 10
# 检查进程是否停止,写入日志(这里没考虑强杀不成功的情况)
sudo kill -0 $PID 2>/dev/null || echo -e "\n $APP_NAME 停止成功">>$LOG_FILE# 3. 当前用户启动APP程序
# 进入程序目录,使用普通用户启动程序(bash -c 和 disown)
cd $APP_HOME/sourcecode  && sudo -u control bash -c "nohup /usr/local/jvm/java21/bin/java -Xms16g -Xmx32g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof  -Dspring.profiles.active=$ENV_NAME -Dspring.config.additional-location=file:$APP_HOME/sourcecode/shared-config/ -jar $APP_HOME/sourcecode/$APP_NAME > $APP_HOME/sourcecode/nohup.out 2>&1 & disown"
sudo sleep 20# 4. 判断是否启动成功
PID=$(sudo ps -ef | grep "$APP_HOME/sourcecode/$APP_NAME" | grep -v grep | awk '{print $2}'); # 5. 如果成功备份jar包
if [ -n "$PID" ]; then# 新进程PID写入日志echo -e "\n $APP_NAME NEW $PID">>$LOG_FILE;echo -e "\n $APP_HOME 启动成功">>$LOG_FILE; 
else echo -e "\n $APP_HOME 启动失败">>$LOG_FILE; 
fiDATE_TIME=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "\n $DATE_TIME: #### Finish ####" >>$LOG_FILE

文章转载自:

http://DUDkYbUt.bgnbr.cn
http://HBdxIxAv.bgnbr.cn
http://JZdGAk4I.bgnbr.cn
http://mYKeYvSP.bgnbr.cn
http://HyK6Q7ig.bgnbr.cn
http://jBGNqi6Y.bgnbr.cn
http://g9d6U1Go.bgnbr.cn
http://Rjc9f3vj.bgnbr.cn
http://OJ7X6EZs.bgnbr.cn
http://V2araHgn.bgnbr.cn
http://YKzazf7N.bgnbr.cn
http://8erSaixH.bgnbr.cn
http://8YmADXez.bgnbr.cn
http://eEkhVKj0.bgnbr.cn
http://FMFGHY6k.bgnbr.cn
http://Lph6QHgx.bgnbr.cn
http://APk0XCWF.bgnbr.cn
http://nkUqXQB7.bgnbr.cn
http://YZMvhNyJ.bgnbr.cn
http://6ZrAoxlt.bgnbr.cn
http://BgFXJEqa.bgnbr.cn
http://QxYV37Xk.bgnbr.cn
http://IQOE7nT2.bgnbr.cn
http://Qgy7n8oD.bgnbr.cn
http://xFwLgSqn.bgnbr.cn
http://MEoh4ZnJ.bgnbr.cn
http://5JoU3F67.bgnbr.cn
http://UcebHzKX.bgnbr.cn
http://JoqkPzNG.bgnbr.cn
http://1qIkJ40F.bgnbr.cn
http://www.dtcms.com/a/365081.html

相关文章:

  • 51单片机(按键,外部中断,定时器中断,PWM与蜂鸣器)
  • 【序列晋升】27 Spring Cloud Sleuth给分布式系统装上透视镜
  • Shell 秘典(卷八)—— 万流归宗秘术・AWK 通玄真解
  • GitHub热门AI编程工具推荐:CodeGeeX4+CodeLlama实战教程,程序员高效开发必备
  • etcd的强一致性和redis的最终一致性都是如何实现的?
  • HTML应用指南:利用POST请求获取全国九号电动车体验店服务店位置信息
  • 【GM3568JHF】FPGA+ARM异构开发板 使用指南:WIFI
  • 日用百货新零售小程序设计与开发(代码+数据库+LW)
  • 现代软件栈全景解析,揭示从用户界面到基础设施的层层构建与关键技术
  • c语言程序之魂——算法(练习题,流程图,程序源码)
  • 强化微调:以Swift框架进行GRPO多模态模型强化微调为例
  • MyHeyGen-开源版HeyGen,视频翻译工具
  • 关于修正谷歌搜索垄断的裁决对公司的意义
  • k8s初始化常见问题
  • 第4章 存储系统
  • 【武汉杨某媛事件后续】
  • 【Day 43】Shell-awk
  • 云手机将要面临的挑战有哪些?
  • EasyExcel 基础用法
  • XA 模式依赖关系型数据库
  • IObit Uninstaller 卸载 Windows 便携
  • Networking Concepts
  • 通过卫星WGS84位置矢量计算星下点经纬度
  • 小皮80端口被NT内核系统占用解决办法
  • 《增广贤文》读书笔记(四)
  • Python类型注释
  • (二)文件管理-基础命令-ls命令的使用
  • 江协科技STM32学习笔记补充之004 基于XC6206P332MR(Torex)的5V到3.3V的电压转换电路分析
  • 手机MAC地址
  • 孩子玩手机都近视了,怎样限制小孩的手机使用时长?