如何在 unix 中守护任意脚本?

Posted

技术标签:

【中文标题】如何在 unix 中守护任意脚本?【英文标题】:How do I daemonize an arbitrary script in unix? 【发布时间】:2010-10-06 05:32:48 【问题描述】:

我想要一个可以将任意通用脚本或命令转换为daemon 的守护程序。

我想处理两种常见的情况:

    我有一个应该永远运行的脚本。如果它死了(或在重新启动时),请重新启动它。不要让两个副本同时运行(检测一个副本是否已经在运行,在这种情况下不要启动它)。

    我有一个简单的脚本或命令行命令,我想永远重复执行(运行之间有短暂的停顿)。同样,不要让脚本的两个副本同时运行。

当然,在案例 2 中围绕脚本编写“while(true)”循环然后为案例 1 应用解决方案是微不足道的,但更通用的解决方案将直接解决案例 2,因为这适用于情况 1 也是(如果脚本不打算死掉,你可能只需要更短的暂停或没有暂停(当然,如果脚本真的确实永远不会死,那么暂停实际上并不重要)) .

请注意,该解决方案不应涉及,例如,向现有脚本添加文件锁定代码或 PID 记录。

更具体地说,我想要一个可以运行的程序“守护进程”

% daemonize myscript arg1 arg2

或者,例如,

% daemonize 'echo `date` >> /tmp/times.txt'

这将保留不断增长的附加到 times.txt 的日期列表。 (请注意,如果 daemonize 的参数是一个像上面的情况 1 一样永远运行的脚本,那么 daemonize 仍然会做正确的事情,在必要时重新启动它。)然后我可以在我的 .login 中放置一个类似上面的命令和/或每小时或每分钟 cron 它(取决于我对它意外死亡的担心程度)。

注意:daemonize 脚本需要记住它正在守护的命令字符串,这样如果再次守护相同的命令字符串,它就不会启动第二个副本。

此外,理想情况下,该解决方案应该适用于 OS X 和 linux,但欢迎使用其中一种或另一种的解决方案。

编辑:如果你必须用sudo daemonize myscript myargs 调用它也没关系。

(如果我认为这一切都错了,或者有快速而肮脏的部分解决方案,我也很想听听。)


PS:如果有用的话,here's 一个类似的特定于 python 的问题。

this 对类似问题的回答似乎是一个有用的成语,可以快速而肮脏地妖魔化任意脚本:

【问题讨论】:

纯shell版本见serverfault.com/questions/311593/… 【参考方案1】:

您可以使用 nohup 和 & 运算符来守护 Unix 中的任何可执行文件:

nohup yourScript.sh script args&

nohup 命令允许您在不杀死脚本的情况下关闭您的 shell 会话,而 & 将您的脚本置于后台,以便您获得 shell 提示以继续您的会话。唯一的小问题是标准输出和标准错误都被发送到./nohup.out,所以如果你在这个庄园中启动几个脚本,它们的输出将交织在一起。更好的命令是:

nohup yourScript.sh script args >script.out 2>script.error&

这会将标准输出发送到您选择的文件,并将标准错误发送到您选择的其他文件。如果您只想对标准输出和标准错误使用一个文件,您可以这样做:

nohup yourScript.sh script args >script.out 2>&1 &

2>&1 告诉 shell 将标准错误(文件描述符 2)重定向到与标准输出(文件描述符 1)相同的文件。

要只运行一次命令并在它死后重新启动它,您可以使用此脚本:

#!/bin/bash

if [[ $# < 1 ]]; then
    echo "Name of pid file not given."
    exit
fi

# Get the pid file's name.
PIDFILE=$1
shift

if [[ $# < 1 ]]; then
    echo "No command given."
    exit
fi

echo "Checking pid in file $PIDFILE."

#Check to see if process running.
PID=$(cat $PIDFILE 2>/dev/null)
if [[ $? = 0 ]]; then
    ps -p $PID >/dev/null 2>&1
    if [[ $? = 0 ]]; then
        echo "Command $1 already running."
        exit
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

# Get command.
COMMAND=$1
shift

# Run command until we're killed.
while true; do
    $COMMAND "$@"
    sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop
done

第一个参数是要使用的 pid 文件的名称。第二个参数是命令。所有其他参数都是命令的参数。

如果您将此脚本命名为restart.sh,您会这样称呼它:

nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &

【讨论】:

太棒了;谢谢。我想知道它是否也应该有一个延迟重启的选项。或者最好将它与它结合使用:***.com/questions/555116/… 这只处理 SIGHUP,还有其他(通常)致命的信号需要处理。 另一种改进此脚本的方法可能是让它自己找到一个放置 $PIDFILE 的好位置,而不是要求将其指定为 arg。它甚至不会自行清理! (使用trap EXIT 应该很简单) 另外,考虑&lt;test 中的使用是ASCII 比较而不是整数比较。它可能仍然有效,但可能会导致错误。 我已经发布了我对这个脚本的修复here。【参考方案2】:

对于冗长的答案,我深表歉意(请参阅 cmets,了解我的答案如何符合规范)。我试图做到全面,所以你有尽可能好的一面。 :-)

如果您能够安装程序(具有 root 访问权限),并且愿意一次性完成设置脚本以执行守护程序(即,比简单地指定要在命令行,但每个服务只需要执行一次),我有一种更强大的方法。

它涉及使用daemontools。这篇文章的其余部分描述了如何使用 daemontools 设置服务。

初始设置

    按照How to install daemontools 中的说明进行操作。一些发行版(例如 Debian、Ubuntu)已经有它的软件包,所以就使用它吧。 创建一个名为/service 的目录。安装程序应该已经这样做了,但只需验证,或者手动安装。如果你不喜欢这个位置,你可以在你的 svscanboot 脚本中更改它,尽管大多数 daemontools 用户习惯使用 /service,如果你不使用它会感到困惑。 如果您使用的是 Ubuntu 或其他不使用标准 init(即不使用 /etc/inittab)的发行版,则需要使用预安装的 inittab 作为安排的基础svscanboot 将由 init 调用。这并不难,但您需要知道如何配置您的操作系统使用的initsvscanboot 是一个调用svscan 的脚本,主要工作是寻找服务;它是从init 调用的,所以init 将安排在它因任何原因死亡时重新启动它。

按服务设置

    每个服务都需要一个服务目录,该目录存储有关服务的内务管理信息。您还可以创建一个位置来存放这些服务目录,以便它们都在一个地方;通常我使用/var/lib/svscan,但任何新位置都可以。

    我通常使用a script来设置服务目录,以节省大量手动重复工作。例如,

    sudo mkservice -d /var/lib/svscan/some-service-name -l -u user -L loguser "command line here"
    

    some-service-name 是您要为服务提供的名称,user 是运行该服务的用户,loguser 是运行记录器的用户。 (稍微解释一下日志记录。)

    您的服务必须在前台运行。如果您的程序默认为背景,但可以选择禁用它,请执行此操作。如果您的程序后台无法禁用它,请阅读fghack,尽管这是一个权衡:您无法再使用svc 控制程序。 编辑run 脚本以确保它按照您的意愿运行。如果您希望您的服务经常退出,您可能需要在顶部拨打sleep 电话。 一切设置正确后,在/service 中创建一个指向您的服务目录的符号链接。 (不要将服务目录直接放在/service 中;这会使从svscan 的手表中删除服务变得更加困难。)

记录

    daemontools 的日志记录方式是让服务将日志消息写入标准输出(或标准错误,如果您使用的是由mkservice 生成的脚本); svscan 负责将日志消息发送到日志服务。 日志服务从标准输入中获取日志消息。 mkservice 生成的日志服务脚本将在log/main 目录中创建自动轮换的、带有时间戳的日志文件。当前日志文件名为current。 日志服务可以独立于主服务启动和停止。 通过tai64nlocal 传送日志文件会将时间戳转换为人类可读的格式。 (TAI64N 是一个以纳秒为单位的 64 位原子时间戳。)

控制服务

    使用svstat 获取服务的状态。请注意,日志服务是独立的,并且有自己的状态。 您可以使用svc 控制您的服务(启动、停止、重新启动等)。例如,要重新启动您的服务,请使用svc -t /service/some-service-name-t 表示“发送SIGTERM”。 其他可用信号包括-h (SIGHUP)、-a (SIGALRM)、-1 (SIGUSR1)、-2 (SIGUSR2) 和@9876543732@ (SIGKILL) @)。 要关闭服务,请使用-d。您还可以通过在服务目录中创建一个名为 down 的文件来防止服务在启动时自动启动。 要启动服务,请使用-u。除非您之前已将其关闭(或将其设置为不自动启动),否则这不是必需的。 要让主管退出,请使用-x;通常与-d 一起使用也可以终止服务。这是允许删除服务的常用方法,但您必须先从/service 取消链接服务,否则svscan 将重新启动主管。 此外,如果您使用日志记录服务 (mkservice -l) 创建了服务,请记住在删除服务目录之前还要退出日志记录主管(例如,svc -dx /var/lib/svscan/some-service-name/log)。

总结

优点:

    daemontools 提供了一种创建和管理服务的防弹方法。我将它用于我的服务器,我强烈推荐它。 其日志记录系统非常强大,服务自动重启工具也是如此。 因为它使用您编写/调整的 shell 脚本启动服务,所以您可以根据需要定制服务。 强大的服务控制工具:您可以向服务发送几乎任何信号,并且可以可靠地启动和关闭服务。 保证您的服务有一个干净的执行环境:它们将在与init 提供的环境、进程限制等相同的环境下执行。

缺点:

    每个服务都需要一些设置。值得庆幸的是,每次服务只需执行一次。 必须将服务设置为在前台运行。此外,为了获得最佳结果,应将它们设置为记录到标准输出/标准错误,而不是 syslog 或其他文件。 如果您不熟悉 daemontools 的工作方式,学习曲线会很陡峭。您必须使用svc 重新启动服务,并且不能直接运行运行脚本(因为它们将不受主管的控制)。 大量的内务管理文件和大量的内务处理流程。每个服务都需要自己的服务目录,每个服务使用一个主管进程在服务死亡时自动重启服务。 (如果您有许多服务,您将在进程表中看到 lotssupervise 进程。)

总的来说,我认为 daemontools 是满足您需求的优秀系统。我欢迎任何关于如何设置和维护它的问题。

【讨论】:

我的回答如何确定规范: 1. 您必须设置服务,因此只要您不设置重复项(并且只要您的服务本身没有背景),就没有重复项会发生。 2. supervise,主管,负责重启任何退出的服务。它在重新启动之间等待一秒钟;如果时间不够,请在服务运行脚本的顶部进入睡眠状态。 2a。 supervise 本身由 svscan 支持,因此如果主管死了,它将重新启动。 2b。 svscaninit 支持,它会根据需要自动重启 svscan。 2c。如果您的init 因任何原因而死,无论如何您都会被搞砸。 :-P 为了回答有关家务的其他问题,daemontools 系统不使用 PID 文件,因为它们可能会过时。相反,所有流程信息都由支持给定服务的主管保存。主管在服务目录中维护了一堆文件(和 FIFO),svstatsvc 等工具可以使用这些文件。 我们应该在 SO 和一般网络中发布更多这样的帖子。不仅仅是一个关于如何达到预期效果的食谱,而是一个不厌其烦地解释食谱的食谱。为什么我不能多次投票? :|【参考方案3】:

你应该看看daemonize。它允许检测第二个副本(但它使用文件锁定机制)。它还适用于不同的 UNIX 和 Linux 发行版。

如果您需要将应用程序作为守护进程自动启动,则需要创建适当的 init-script。

您可以使用以下模板:

#!/bin/sh
#
# mydaemon     This shell script takes care of starting and stopping
#               the <mydaemon>
#

# Source function library
. /etc/rc.d/init.d/functions


# Do preliminary checks here, if any
#### START of preliminary checks #########


##### END of preliminary checks #######


# Handle manual control parameters like start, stop, status, restart, etc.

case "$1" in
  start)
    # Start daemons.

    echo -n $"Starting <mydaemon> daemon: "
    echo
    daemon <mydaemon>
    echo
    ;;

  stop)
    # Stop daemons.
    echo -n $"Shutting down <mydaemon>: "
    killproc <mydaemon>
    echo

    # Do clean-up works here like removing pid files from /var/run, etc.
    ;;
  status)
    status <mydaemon>

    ;;
  restart)
    $0 stop
    $0 start
    ;;

  *)
    echo $"Usage: $0 start|stop|status|restart"
    exit 1
esac

exit 0

【讨论】:

看起来是正确答案的候选者。特别是考虑到它的“单实例检查”。 这可能是最好的答案——我不确定——但如果你认为是,你能否解释一下为什么我在问题中给出的规范是错误的? 我不喜欢停止部分的killproc:如果你有一个进程运行javakillproc 将导致所有其他Java 进程也被杀死. 从 /etc/rc.d/init.d/functions,daemonize 只是从一个新的 shell 启动二进制文件: $cgroup $nice /bin/bash -c $corelimit &gt;/dev/null 2&gt;&amp;1 ; $* 所以我怀疑它会继续守护任何东西...... 我知道这是旧的,但对于以后发现它的任何人......这是正确的。 /etc/init.d/functions 中定义的“守护进程”实际上 not 为您守护进程。它只是做 cgroups、检查进程是否已经在运行、设置用户、设置 nice 和 ulimit 值等的包装器。它为你守护进程。那仍然是你自己的工作。 :)【参考方案4】:

我想你可能想试试start-stop-daemon(8)。在任何 Linux 发行版中查看 /etc/init.d 中的脚本以获取示例。它可以通过调用的命令行或 PID 文件找到已启动的进程,因此它符合您的所有要求,除了作为脚本的看门狗。但您始终可以启动另一个守护程序看门狗脚本,在必要时重新启动您的脚本。

【讨论】:

Fedora 中还没有启动-停止-守护进程,因此依赖于它的脚本是不可移植的。见:fedoraproject.org/wiki/Features/start-stop-daemon 对于 OSX 用户的提醒:那里也没有 start-stop-daemon(从 10.9 开始)。 @mklement0 嗯...近 5 年发生了很多变化。 我的,时间过得真快。不过,start-stop-daemon 仍然活跃在 Linux 上;但在阅读答案***.com/a/525406/45375 后,我意识到OSX 做了自己的事情:launchd【参考方案5】:

作为已经提到的daemonizedaemontools 的替代方案,还有libslack 包的daemon 命令。

daemon 非常可配置,并且确实关心所有繁琐的守护进程,例如自动重启、日志记录或 pidfile 处理。

【讨论】:

【参考方案6】:

如果你专门使用 OS X,我建议你看看 launchd 是如何工作的。它将自动检查以确保您的脚本正在运行,并在必要时重新启动它。它还包括各种调度功能等。它应该同时满足要求1和2。

至于确保您的脚本只能运行一个副本,您需要使用 PID 文件。通常我将一个文件写入 /var/run/.pid ,其中包含当前正在运行的实例的 PID。如果程序运行时文件存在,它会检查文件中的 PID 是否实际运行(程序可能已经崩溃或忘记删除 PID 文件)。如果是,则中止。如果没有,开始运行并覆盖 PID 文件。

【讨论】:

【参考方案7】:

Daemontools (http://cr.yp.to/daemontools.html) 是一组用于执行此操作的非常核心的实用程序,由 dj bernstein 编写。我已经成功地使用了它。令人讨厌的部分是,当您运行它们时,没有任何脚本返回任何可见的结果 - 只是不可见的返回码。但是一旦运行起来,它就是防弹的。

【讨论】:

是的,我也打算写一个使用 daemontools 的条目。我会写我自己的帖子,因为我希望我的答案更加全面,并希望以这种方式获得赏金。走着瞧。 :-)【参考方案8】:

首先从http://code.activestate.com/recipes/278731/获取createDaemon()

然后是主要代码:

import subprocess
import sys
import time

createDaemon()

while True:
    subprocess.call(" ".join(sys.argv[1:]),shell=True)
    time.sleep(10)

【讨论】:

哦,谢谢!想让它更通用一点,以便您可以执行“daemonize foo arg1 arg2”和“daemonize 'foo arg1 arg2'”? 好的,它现在将加入参数 - 但是如果您想在参数中包含空格,则必须更改它。 谢谢道格拉斯!但是有一个很大的缺陷:运行两次“daemonize foo”会启动两个 foo 副本。 您可以添加一些 PID 记录代码,但最好只运行一次脚本... 我认为这是整个“守护进程”包装概念的基础。 (例如,我可以每小时或每分钟 cron 来确保它一直在运行。)我想错了吗? createDaemon 是否已经以某种方式保证了这一点?重启后呢?【参考方案9】:

这是一个完整的工作版本,您可以将其复制到一个空目录并试用(在安装 CPAN 依赖项后,它们是 Getopt::Long、File::Spec、File::Pid 和 IPC::System::Simple --所有这些都非常标准,强烈推荐给任何黑客:您可以使用cpan &lt;modulename&gt; &lt;modulename&gt; ... 一次性安装它们。


keepAlive.pl:

#!/usr/bin/perl

# Usage:
# 1. put this in your crontab, to run every minute:
#     keepAlive.pl --pidfile=<pidfile> --command=<executable> <arguments>
# 2. put this code somewhere near the beginning of your script,
#    where $pidfile is the same value as used in the cron job above:
#     use File::Pid;
#     File::Pid->new(file => $pidfile)->write;

# if you want to stop your program from restarting, you must first disable the
# cron job, then manually stop your script. There is no need to clean up the
# pidfile; it will be cleaned up automatically when you next call
# keepAlive.pl.

use strict;
use warnings;

use Getopt::Long;
use File::Spec;
use File::Pid;
use IPC::System::Simple qw(system);

my ($pid_file, $command);
GetOptions("pidfile=s"   => \$pid_file,
           "command=s"   => \$command)
    or print "Usage: $0 --pidfile=<pidfile> --command=<executable> <arguments>\n", exit;

my @arguments = @ARGV;

# check if process is still running
my $pid_obj = File::Pid->new(file => $pid_file);

if ($pid_obj->running())

    # process is still running; nothing to do!
    exit 0;


# no? restart it
print "Pid " . $pid_obj->pid . " no longer running; restarting $command @arguments\n";

system($command, @arguments);

example.pl:

#!/usr/bin/perl

use strict;
use warnings;

use File::Pid;
File::Pid->new(file => "pidfile")->write;

print "$0 got arguments: @ARGV\n";

现在您可以使用./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3 调用上面的示例,并且将创建文件pidfile,您将看到输出:

Pid <random number here> no longer running; restarting ./example.pl 1 2 3
./example.pl got arguments: 1 2 3

【讨论】:

如果我理解正确的话,我相信这并不完全符合规范。在您的解决方案中(谢谢,顺便说一句!)必须修改要守护进程的程序以将其 PID 写入 PID 文件。我希望有一个可以守护任意脚本的实用程序。 @dreeves: 是的,但是有两种方法可以解决这个问题:1. keepAlive.pl 调用的脚本(例如 example.pl)可能只是一个执行真实程序的包装器,或者 2. keepAlive.pl 可以解析活动系统进程表(使用 CPAN 的 Proc::ProcessTable)以尝试找到相关进程及其 pid)。【参考方案10】:

您也可以试试Monit。 Monit 是一项监视和报告其他服务的服务。虽然它主要用作通知(通过电子邮件和短信)有关运行时问题的一种方式,但它也可以执行这里大多数其他建议所提倡的。它可以自动(重新)启动和停止程序、发送电子邮件、启动其他脚本以及维护您可以获取的输出日志。此外,我发现它很容易安装和维护,因为它有可靠的文档。

【讨论】:

【参考方案11】:

你可以试试immortal 它是一个 *nix 跨平台(与操作系统无关)主管。

在 macOS 上快速尝试:

brew install immortal

如果您从端口使用 FreeBSD 或使用 pkg:

pkg install immortal

对于Linux,通过下载预编译的二进制文件或从源代码:https://immortal.run/source/

你可以像这样使用它:

immortal -l /var/log/date.log date

或通过configuration YAML 文件为您提供更多选项,例如:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log

如果您还想将标准错误输出保存在单独的文件中,您可以使用以下内容:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
stderr:
    file: /var/log/date-error.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log

【讨论】:

【参考方案12】:

我对@9​​87654321@做了一系列改进。

    此脚本中的标准输出完全由来自其子级的标准输出组成,除非它因检测到该命令已在运行而退出 在其 pidfile 终止后清理 可选的可配置超时期限(接受任何正数参数,发送至sleep-h 上的使用提示 任意命令执行,而不是单个命令执行。最后一个 arg 或剩余的 args(如果有多个最后一个 args)被发送到eval,因此您可以将任何类型的 shell 脚本作为字符串发送到该脚本作为最后一个 arg(或尾随 args)守护进程 使用-lt 而不是&lt; 完成的参数计数比较

这是脚本:

#!/bin/sh

# this script builds a mini-daemon, which isn't a real daemon because it
# should die when the owning terminal dies, but what makes it useful is
# that it will restart the command given to it when it completes, with a
# configurable timeout period elapsing before doing so.

if [ "$1" = '-h' ]; then
    echo "timeout defaults to 1 sec.\nUsage: $(basename "$0") sentinel-pidfile [timeout] command [command arg [more command args...]]"
    exit
fi

if [ $# -lt 2 ]; then
    echo "No command given."
    exit
fi

PIDFILE=$1
shift

TIMEOUT=1
if [[ $1 =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
        TIMEOUT=$1
        [ $# -lt 2 ] && echo "No command given (timeout was given)." && exit
        shift
fi

echo "Checking pid in file $PIDFILE." >&2

#Check to see if process running.
if [ -f "$PIDFILE" ]; then
    PID=$(< $PIDFILE)
    if [ $? = 0 ]; then
        ps -p $PID >/dev/null 2>&1
        if [ $? = 0 ]; then
            echo "This script is (probably) already running as PID $PID."
            exit
        fi
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

cleanup() 
        rm $PIDFILE

trap cleanup EXIT

# Run command until we're killed.
while true; do
    eval "$@"
    echo "I am $$ and my child has exited; restart in $TIMEOUTs" >&2
    sleep $TIMEOUT
done

用法:

$ term-daemonize.sh pidfilefortesting 0.5 'echo abcd | sed s/b/zzz/'
Checking pid in file pidfilefortesting.
azzzcd
I am 79281 and my child has exited; restart in 0.5s
azzzcd
I am 79281 and my child has exited; restart in 0.5s
azzzcd
I am 79281 and my child has exited; restart in 0.5s
^C

$ term-daemonize.sh pidfilefortesting 0.5 'echo abcd | sed s/b/zzz/' 2>/dev/null
azzzcd
azzzcd
azzzcd
^C

请注意,如果您从不同的目录运行此脚本,它可能会使用不同的 pidfile,并且不会检测到任何现有的正在运行的实例。由于它旨在运行和重新启动通过参数提供的临时命令,因此无法知道某事是否已经启动,因为谁能说它是否是相同的命令?为了改进这种只运行单个实例的强制执行,需要针对具体情况的解决方案。

此外,要使其充当适当的守护程序,您必须(至少)使用 nohup 作为其他答案提到的。我没有努力为过程可能收到的信号提供任何弹性。

还有一点需要注意的是,杀死这个脚本(如果它是从另一个被杀死的脚本调用的,或者有一个信号)可能无法成功杀死孩子,特别是如果孩子还另一个 脚本。我不确定这是为什么,但这似乎与eval 的工作方式有关,这对我来说很神秘。因此,谨慎的做法是将该行替换为仅接受单个命令的内容,例如另一个答案。

【讨论】:

【参考方案13】:

还有一个非常简单的双叉 + setsid 方法可以将任何脚本与其父进程分离

( setsid my-regular-script arg [arg ...] 1>stdout.log 2>stderr.log & )

setsid 是标准util-linux 包的一部分,自诞生之日起就与Linux 一起使用。这在我知道的任何POSIX 兼容的 shell 中启动时都有效。

另一种基于双叉的方法甚至不需要任何额外的可执行文件或包,并且完全依赖于基于 POSIX 的 shell

( my-regular-script arg [arg ...] 1>stdout.log 2>stderr.log & ) &

当父进程离开阶段时,它也可以成为孤儿

【讨论】:

以上是关于如何在 unix 中守护任意脚本?的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Python 脚本像 Linux 中的服务或守护程序一样运行

如何将我的php脚本以守护进程的方式一直运行

当父进程在python中终止时如何避免进程终止

如何将我的php脚本以守护进程的方式一直运行

如何守护 Java 程序?

我如何清理我的守护进程?