我正在写一个外壳脚本我想在启动时作为守护进程运行不使用外部工具,例如守护进程工具或者守护进程。
Linux 守护进程编写 HOWTO
根据Linux 守护进程编写 HOWTO, A恰当的守护进程具有以下特点:
- 叉子来自父进程
- 关闭全部文件描述符(IE,
stdin
,stdout
,stderr
) - 打开日志用于写入(如果配置)
- 改变了工作目录一个持久的(通常
/
) - 重置文件模式掩码(掩码)
- 创造出独特的会话ID(安全识别号)
守护进程介绍
这守护进程介绍更进一步,指出典型的守护进程还:
- 与其脱离关系控制终端(如果有的话)并忽略所有终端信号
- 与其脱离关系进程组
- 把手
SIGCLD
我如何仅使用常见的 Linux 工具在sh
、dash
或脚本中完成所有这些操作?bash
该脚本应该能够在尽可能多的发行版上运行,而无需额外的软件,尽管德班是我们的首要关注点。
笔记:我知道网上有很多答案堆栈交换网络建议使用nohup
或setsid
,但是这些方法都不能满足上述所有要求。
编辑:这守护进程(7) 联机帮助页还给出了一些指示,尽管旧式SysV
守护进程和新式systemd
守护进程之间似乎存在一些差异。由于与各种发行版的兼容性很重要,因此请确保答案明确任何差异。
答案1
使用系统您应该能够通过创建一个简单的单元来将脚本作为守护进程运行。有很多不同的选项您可以添加,但这已经是最简单的了。
假设你有一个脚本/usr/bin/mydaemon
。
#!/bin/sh
while true; do
date;
sleep 60;
done
别忘了sudo chmod +x /usr/bin/mydaemon
。
创建一个单位/etc/systemd/system/mydaemon.service
。
[Unit]
Description=My daemon
[Service]
ExecStart=/usr/bin/mydaemon
Restart=on-failure
[Install]
WantedBy=multi-user.target
启动守护进程运行
systemctl start mydaemon.service
要在引导时启动它,请启用它
systemctl enable mydaemon.service
如果在基于 systemd 的系统(当今大多数 Linux 发行版都是如此)上,这并不是真正的外部工具。缺点是它不会在所有地方都有效。
答案2
我可能在这里遗漏了一些东西;为什么不合适呢nohup
?当然还不够独自的,但补充它似乎很简单。
#!/bin/bash
if [ "$1" = "DAEMON" ]; then
# is this necessary? Add other signals at will (TTIN TTOU INT STOP TSTP)
trap '' INT
cd /tmp
shift
### daemonized section ######
for i in $( seq 1 10 ); do
date
sleep 5
done
#### end of daemonized section ####
exit 0
fi
export PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
umask 022
# You can add nice and ionice before nohup but they might not be installed
nohup setsid $0 DAEMON $* 2>/var/log/mydaemon.err >/var/log/mydaemon.log &
据我所知:
- 输出被适当重定向(如有必要,请使用 /dev/null)
- umask 是继承的
stdin
无论如何都会在父脚本结束时死亡- daemon.sh 脚本的父级重新设置为
init
(或systemd
)
我有一种强烈的感觉,我错过了显而易见的事情。投反对票,但请告诉我它是什么:-)
答案3
大多数发行版中包含的Linuxscreen
命令可以守护 shell 脚本。我经常使用它。这是一个启动、列出和退出分离屏幕会话的快速示例......
# screen -dmS Session_Name bash -c "while true; do date; sleep 60; done"
# screen -ls
There are screens on:
8534.Session_Name (04/04/2018 08:46:27 PM) (Detached)
# screen -S Session_Name -X quit