/ Technical / 14浏览

Linux优雅的使用后台启动脚本

在Linux环境下,常常会使用一些脚本,但我们想使其后台长期运行,需要使用Linux的终端命令,使其即使在shell终端关了之后依然执行脚本,并可以将日志重定向到日志文件。本文章将以启动一个本地脚本my_script.sh为例子,介绍三种常用后台启动方法。

1. tmux / screen(推荐用于开发与可视化监控)

tmux / screen 是终端复用器:它创建一个独立于 SSH 会话的会话(session),在该会话中启动的所有进程都与该会话的伪终端(pty)绑定。即使 SSH 断开,tmux 会话仍在后台运行,随后可以重新 attach 回来查看输出或交互。

  • 关键点:进程不依赖于当前 SSH 终端;你可以随时 detach/reattach。

  • 启动命令:

# 新建 session 并进入
tmux new -s new_session
# 在 tmux 里运行(示例)
bash ./my_script.sh > run.log 2>&1
# 按 Ctrl-b d 退出(detach),任务继续运行
  • 重连:

tmux ls                # 列出 sessions
tmux attach -t new_session    # 重新 attach
  • 终止会话:

# 在会话里 ctrl-c 或 kill pid;或从外部:
tmux kill-session -t new_session

2. setsid 完全脱离会话(推荐用于一次性彻底脱离)

setsid 在 Linux 中用来创建一个新的 session 并使调用进程成为新 session 的 leader。被 setsid 启动的进程 不再属于原来的控制终端,因此终端关闭不会向其发送 SIGHUP(除非另有外力)。配合把 stdin 重定向到 /dev/null 并将 stdout/stderr 重定向到文件,能最大程度保证进程不受终端影响。

  • 关键点:改变 session/pgid,使进程彻底脱离原来终端的进程组和会话。但是无法像 tmux 那样重连查看交互终端(需查看日志文件)。不能防止 SIGTERM/SIGKILL 或外部调度器杀掉进程

  • 启动命令:

# 推荐一行(创建 PID 文件,重定向 stdin)
setsid bash ./my_script.sh > run.log 2>&1 < /dev/null & echo $! > ./my_script.pid
  • 终止进程:

kill $(cat ./my_script.pid)
# 若无响应,强杀:
kill -9 $(cat .my_script.pid)
  • 注意:

    • 一定要加 < /dev/null 避免进程在需要 stdin 时阻塞或在终端关闭时行为异常。

    • 若脚本内再 fork 出子进程,确保这些子进程正确 inherit session/pgid(通常正常)。

    • 若程序在内部又自行设置 signal handler 或恢复 SIGHUP,则需要在程序内或 wrapper 脚本中处理。

3. nohup + disown + 重定向 stdin(常用但比 setsid 容易出坑)

nohup 会把进程的 SIGHUP 信号忽略(signal disposition 设为 IGN),并在必要时把 stdout 重定向到 nohup.outdisown(shell 内置)把一个后台作业从 shell 的作业表中移除,防止 shell 退出时再次向作业发送信号。配合 &(后台运行)和重定向 stdin,可实现脱离会话运行。

  • 关键点nohup 防止 SIGHUP;disown 防止 shell 在终止时管理作业;< /dev/null 防止 stdin 问题。命令简单、兼容性好(几乎所有 Unix shell 都支持)。适合快速后台化任务。

  • 缺点:

    • 对复杂 pipeline 支持差(nohup cmd | tee 只对左侧 cmd 无效,pipe 中其他命令可能被终止)。

    • 仍然不能防 SIGTERM/SIGKILL、不能保证子进程行为(比 setsid 更脆弱)。

    • 需要注意把 stdin 重定向并 disown,否则可能失败。

  • 启动命令:

nohup bash ./my_script.sh > run.log 2>&1 < /dev/null & echo $! > ./my_script.pid; disown
  • 注意:

    • 使用 & 后,用 echo $! 记录 PID(如上)。

    • 如果脚本使用管道(|),请确认 pipe 中的所有命令都能在无终端下正确运行,或避免管道。

    • nohup 会把输出写 nohup.out(若没有显式重定向),建议明确重定向到你的日志文件。

达达下雨不吃鱼
Nvidia驱动安装与升级详细说明
服务器运维踩坑指南
Git子模块的使用
Python全能依赖管理器pixi
零信任点对点组网——Netbird
Python极速环境依赖管理工具uv