Contents

以守护进程身份运行Bash脚本

1. 概述

在本教程中,我们将学习如何在后台将 bash 脚本作为守护进程运行。

2. 以普通用户身份守护脚本

我们可以利用 bash 进程在后台运行我们的脚本。我们使用*&*运算符启动后台任务或进程。

例如,让我们守护这个我们放置在*/home/blogdemo/script.sh*的简单脚本:

# Print a message every 60 seconds.
while :; do
    sleep 60
    echo "Slept for 60 seconds!"
done

使用nohup 命令运行脚本可确保在我们退出终端时它不会被杀死:

$ nohup ./script.sh &
nohup: appending output to nohup.out

nohup将脚本的任何输出记录到nohup.out文件中:

$ cat nohup.out 
Slept for 60 seconds!
Slept for 60 seconds!
...

我们可以在启动脚本后关闭终端。

为了杀死进程,我们可以将启动进程的 PID 记录到一个文件中,并与kill 一起使用:

$ nohup ./script.sh &
nohup: appending output to nohup.out
$ echo $! > ./script.pid
$ cat script.pid
4946

*$!*变量存储新启动进程的PID。因此,我们可以直接杀死脚本:

$ kill $(cat ./script.pid)

虽然我们在这里看到的方法很简单,但它确实需要额外的用户干预来启动和关闭脚本。

3. 守护脚本系统范围

我们刚刚学习了如何以普通用户的身份在后台运行脚本。现在,我们将介绍更复杂的方法,这些方法允许我们通过系统的服务管理器控制脚本。

3.1. 使用systemd

**我们可以使用systemd 单元文件 在启动时启动我们的脚本。**单元文件描述了系统应该如何执行给定的程序。

让我们在*/etc/systemd/system/script_daemon.service*创建一个单元文件:

[Unit]
Description=Script Daemon
[Service]
Type=simple
User=blogdemo
ExecStart=/home/blogdemo/script.sh
Restart=on-failure
[Install]
WantedBy=default.target

我们使用*User=选项设置脚本将运行的用户,并使用ExecStart=*选项设置脚本的路径。systemd.exec 手册页中记录了各种选项。 现在,让我们启用该服务:

$ sudo systemctl daemon-reload
$ sudo systemctl enable script_daemon.service
Created symlink /etc/systemd/system/shutdown.target.wants/script_daemon.service → /etc/systemd/system/script_daemon.service

在这里,我们重新加载systemd配置并使用systemctl 工具启用我们的服务,该工具有助于管理systemd服务。

我们还可以将依赖项添加到各种其他服务。

例如,我们可能希望在启动脚本之前确保网络可用。我们使用*After=*选项执行此操作:

[Unit]
Description=Script Daemon
After=network.target
[Service]
...

我们可以使用sudo systemctl restart script_daemon.service 重启服务。它将在启动时自动启动。

3.2. 使用*/etc/rc.local*

/etc/rc.local文件包含我们要运行的命令。因此,我们可以将脚本的路径附加到这个文件中:

$ echo "/home/blogdemo/script.sh" >> /etc/rc.local

默认情况下,该脚本以root用户身份执行。为了删除权限,我们可以使用su 以不同的用户身份执行命令:

$ echo "su - blogdemo /home/blogdemo/script.sh" >> /etc/rc.local

我们应该注意,该命令应该是从/etc/rc.local*运行的最后一个命令,因为它会阻止执行。*

为了使它成为非阻塞的,我们可以使用nohup命令和我们之前了解的*&*运算符。

此外,如果systemd可用,我们应该避免使用/etc/rc.local*文件的这种方法,因为它是一个遗留文件。*