You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何规范实现Shell脚本作为守护进程启动(无需外部工具)

嘿,我正好研究过符合《Linux守护进程编写指南》规范的Shell守护进程实现,不用daemontools或daemonize这类外部工具完全没问题,咱们一步步来拆解实现:

规范Shell守护进程的核心步骤

按照指南要求,一个标准守护进程需要完成以下关键操作,我会结合代码示例逐个说明:

1. Fork子进程并让父进程退出

这一步是为了让进程脱离当前终端的控制,成为后台进程的基础:

# 第一次fork,脱离父进程
fork
if [ $? -ne 0 ]; then
    exit 1  # fork失败直接退出
fi
# 父进程退出,让子进程成为孤儿进程,由init/systemd接管
exit 0

2. 创建新会话(setsid)

这一步会让进程脱离原会话组和终端,彻底成为独立的会话领导者:

setsid

3. 切换到持久化工作目录

通常切换到根目录/,避免因为原工作目录被卸载导致进程异常:

cd /

4. 重置文件模式掩码(umask)

重置umask可以确保守护进程创建的文件权限符合预期,比如设置为022(默认文件权限644,目录755):

umask 022

5. 关闭所有不必要的文件描述符

默认继承的stdin、stdout、stderr不再需要,直接关闭,避免占用资源:

# 关闭标准输入、输出、错误描述符
exec 0>&-
exec 1>&-
exec 2>&-

6. 重定向输出到日志文件(可选但推荐)

如果需要记录日志,可以把stdout和stderr重定向到指定日志文件:

# 日志文件路径可根据需求修改
LOG_FILE="/var/log/my_daemon.log"
# 重定向stdout和stderr到日志文件,追加模式
exec 1>>"$LOG_FILE" 2>&1

7. 处理信号实现优雅退出

为了让守护进程能被正常终止,最好捕获SIGTERM等信号,执行清理操作:

# 定义信号处理函数
cleanup() {
    echo "Daemon is shutting down..."
    # 这里添加你的清理逻辑,比如关闭文件、释放资源等
    exit 0
}

# 捕获SIGTERM、SIGINT信号
trap cleanup SIGTERM SIGINT
完整的Shell守护进程示例

把上面的步骤整合起来,一个完整的守护进程脚本大概是这样:

#!/bin/bash

# 守护进程主逻辑
daemon_main() {
    while true; do
        # 这里替换成你的实际业务逻辑,比如每隔10秒打印一次日志
        echo "Daemon is running at $(date)"
        sleep 10
    done
}

# 启动守护进程
start_daemon() {
    # 第一步:Fork子进程
    fork
    if [ $? -ne 0 ]; then
        echo "Failed to fork process" >&2
        exit 1
    fi
    exit 0  # 父进程退出

    # 以下是子进程执行的逻辑
    setsid  # 创建新会话
    cd /    # 切换工作目录
    umask 022  # 重置umask

    # 关闭标准文件描述符
    exec 0>&-
    exec 1>&-
    exec 2>&-

    # 重定向输出到日志
    LOG_FILE="/var/log/my_daemon.log"
    exec 1>>"$LOG_FILE" 2>&1

    # 设置信号捕获
    trap 'echo "Shutting down..."; exit 0' SIGTERM SIGINT

    # 执行主逻辑
    daemon_main
}

# 根据参数执行对应操作
case "$1" in
    start)
        start_daemon
        ;;
    stop)
        # 通过进程名查找PID并发送终止信号
        PID=$(pgrep -f "$0")
        if [ -n "$PID" ]; then
            kill "$PID"
            echo "Daemon stopped"
        else
            echo "Daemon is not running" >&2
        fi
        ;;
    status)
        if pgrep -f "$0" >/dev/null; then
            echo "Daemon is running"
        else
            echo "Daemon is not running"
        fi
        ;;
    *)
        echo "Usage: $0 {start|stop|status}" >&2
        exit 1
        ;;
esac
设置开机自启

如果要让这个脚本在系统启动时自动运行,推荐用systemd(现代Linux发行版默认):

  1. 创建一个systemd服务文件,比如/etc/systemd/system/my_daemon.service:
[Unit]
Description=My Custom Shell Daemon
After=network.target

[Service]
Type=forking
ExecStart=/path/to/your/daemon_script.sh start
ExecStop=/path/to/your/daemon_script.sh stop
Restart=always

[Install]
WantedBy=multi-user.target
  1. 重新加载systemd配置并启用服务:
sudo systemctl daemon-reload
sudo systemctl enable --now my_daemon.service

这样你的Shell脚本就完全符合规范,成为一个独立的守护进程,并且能开机自动运行了。

内容的提问来源于stack exchange,提问作者user339676

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:37:12