如何在Python脚本中调用nohup命令启动后台持久运行的进程
Python中调用nohup实现进程后台常驻的解决方案
要实现从Python脚本启动的进程在用户登出后仍正常运行,核心逻辑是让子进程脱离当前用户会话的进程组,不受会话结束时发送的SIGHUP信号影响,以下是两种可直接落地的实现方案:
方案1:直接调用nohup命令
使用Python标准库subprocess调用nohup即可,无需额外依赖,示例代码如下:
import subprocess import os # 封装单个后台进程启动逻辑 def run_nohup_script(script_path, log_path="/dev/null"): # 构造命令,不需要手动加末尾的&,Popen本身支持后台运行 cmd = ["nohup", "python3", script_path] # 重定向输出到指定日志文件,避免默认生成nohup.out with open(log_path, "a") as log_f: subprocess.Popen( cmd, stdout=log_f, stderr=subprocess.STDOUT, preexec_fn=os.setpgrp, # 给子进程创建独立进程组,脱离当前会话 close_fds=True # 关闭从父进程继承的文件描述符,彻底解除关联 ) # 批量启动多个脚本示例 if __name__ == "__main__": script_list = [ "my_script1.py", "my_script2.py", "my_script3.py" ] for index, script in enumerate(script_list): run_nohup_script(script, log_path=f"./script_{index}.log") print("所有后台进程已启动")
方案2:不依赖nohup的原生实现
如果不想调用外部nohup命令,可以通过Python原生配置实现相同效果,本质是手动配置子进程脱离会话、忽略挂断信号:
import subprocess import os import signal def run_daemon_script(script_path, log_path="/dev/null"): def pre_exec_config(): signal.signal(signal.SIGHUP, signal.SIG_IGN) # 忽略SIGHUP信号 os.setsid() # 创建新的会话,完全脱离父会话 os.chdir("/") # 切换工作目录,避免占用父进程的挂载路径 os.umask(0) # 重设文件权限掩码,避免继承父进程的权限限制 with open(log_path, "a") as log_f: subprocess.Popen( ["python3", script_path], stdout=log_f, stderr=subprocess.STDOUT, preexec_fn=pre_exec_config, close_fds=True )
注意事项
- 不要使用
subprocess.run、subprocess.call这类阻塞接口,它们会等待子进程执行结束,不符合后台运行需求 - 如果脚本依赖特定虚拟环境,要把命令中的
python3替换为虚拟环境Python解释器的绝对路径,避免环境变量不匹配导致启动失败 - 日志路径、脚本路径尽量使用绝对路径,避免相对路径找不到文件的问题
- 验证效果可以先执行
ps -ef | grep 你的脚本名记录进程ID,登出后重新登录执行相同命令,进程ID不变则说明配置生效
内容的提问来源于stack exchange,提问作者neisor
相关产品推荐
相关产品推荐

