web-dev-qa-db-de.com

Wie dämonisiere ich ein beliebiges Skript in Unix?

Ich hätte gerne einen Daemonizer, der ein beliebiges, generisches Skript oder einen Befehl in einen Daemon umwandeln kann.

Es gibt zwei häufige Fälle, mit denen ich mich beschäftigen möchte:

  1. Ich habe ein Skript, das für immer ausgeführt werden sollte. Wenn es jemals stirbt (oder beim Neustart), starten Sie es neu. Lassen Sie niemals zu, dass zwei Kopien gleichzeitig ausgeführt werden (prüfen Sie, ob bereits eine Kopie ausgeführt wird, und starten Sie sie in diesem Fall nicht).

  2. Ich habe ein einfaches Skript oder einen Befehlszeilenbefehl, den ich immer wieder ausführen möchte (mit einer kurzen Pause zwischen den Läufen). Lassen Sie auch hier nicht zu, dass zwei Kopien des Skripts gleichzeitig ausgeführt werden.

Natürlich ist es trivial, in Fall 2 eine "while (true)" - Schleife um das Skript zu schreiben und dann eine Lösung für Fall 1 anzuwenden, aber eine allgemeinere Lösung löst nur Fall 2 direkt, da dies für das Skript in Fall 1 gilt gut (Sie möchten vielleicht nur eine kürzere oder keine Pause, wenn das Skript nicht sterben soll (natürlich, wenn das Skript wirklichniemals stirbt, dann spielt die Pause eigentlich keine Rolle).

Beachten Sie, dass die Lösung beispielsweise nicht das Hinzufügen von Dateisperrcode oder PID-Aufzeichnung zu den vorhandenen Skripten beinhalten sollte.

Genauer gesagt, ich möchte ein Programm "daemonisieren", wie ich es ausführen kann

% daemonize myscript arg1 arg2

oder zum Beispiel

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

in diesem Fall wird eine wachsende Liste von Daten an times.txt angehängt. (Beachten Sie, dass, wenn das Argument (die Argumente) zum Dämonisieren ein Skript ist, das wie in Fall 1 oben für immer ausgeführt wird, Dämonisieren immer noch das Richtige tut und es bei Bedarf neu startet.) Ich könnte dann einen Befehl wie oben in mein .login einfügen und/oder cron es stündlich oder minutiös (je nachdem, wie besorgt ich war, dass es unerwartet stirbt).

NB: Das Daemonize-Skript muss sich die Befehlszeichenfolge merken, die es daemonisiert, damit beim erneuten Daemonisieren derselben Befehlszeichenfolge keine zweite Kopie gestartet wird.

Auch sollte die Lösung idealerweise sowohl unter OS X als auch unter Linux funktionieren, aber Lösungen für das eine oder andere sind willkommen.

BEARBEITEN: Es ist in Ordnung, wenn Sie es mit Sudo daemonize myscript myargs aufrufen müssen.

(Wenn ich daran denke, dass alles falsch ist oder es schnelle und schmutzige Teillösungen gibt, würde ich das auch gerne hören.)


PS: Falls es nützlich ist, hier ist eine ähnliche Frage speziell für Python.

Und diese Antwort auf eine ähnliche Frage hat eine nützliche Redewendung für eine schnelle und schmutzige Dämonisierung eines beliebigen Skripts:

90
dreeves

Sie können jede ausführbare Datei in Unix mit Nohup und dem Operator & unterzeichnen:

Nohup yourScript.sh script args&

Mit dem Befehl Nohup können Sie Ihre Shell-Sitzung beenden, ohne dass das Skript abgebrochen wird. Wenn Sie das Skript & jedoch in den Hintergrund stellen, wird eine Shell-Eingabeaufforderung angezeigt, mit der Sie die Sitzung fortsetzen können. Das einzige kleinere Problem dabei ist Standard out und beide Standardfehler werden an ./Nohup.out gesendet. Wenn Sie also mehrere Skripts in diesem Manor starten, wird deren Ausgabe miteinander verknüpft. Ein besserer Befehl wäre:

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

Dies sendet Standard zu einer Datei Ihrer Wahl und Standardfehler zu einer anderen Datei Ihrer Wahl. Wenn Sie nur eine Datei für den Standardausgang und den Standardfehler verwenden möchten, können Sie dies tun:

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

Die 2> & 1-Anweisung weist die Shell an, den Standardfehler (Dateideskriptor 2) auf dieselbe Datei umzuleiten wie der Standardausgang (Dateideskriptor 1).

Um einen Befehl nur einmal auszuführen und ihn neu zu starten, können Sie das folgende Skript verwenden:

#!/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 "[email protected]"
    sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop
done

Das erste Argument ist der Name der zu verwendenden PID-Datei. Das zweite Argument ist der Befehl. Alle anderen Argumente sind die Argumente des Befehls.

Wenn Sie das Skript restart.sh nennen, würden Sie es wie folgt nennen:

Nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &
86
Robert Menteer

Ich entschuldige mich für die lange Antwort (bitte beachten Sie die Kommentare dazu, wie meine Antwort die Spezifikation festhält). Ich versuche, umfassend zu sein, damit Sie so gut wie möglich in der Höhe sind. :-)

Wenn Sie in der Lage sind, Programme zu installieren (Root-Zugriff) und bereit sind, einmalige Vorbereitungen zum Einrichten Ihres Skripts für die Daemon-Ausführung zu treffen (dh mehr als nur die Befehlszeilenargumente anzugeben, die in der Befehlszeile ausgeführt werden sollen), Ich muss es aber nur einmal pro Service machen. Ich habe einen robusteren Weg.

Es beinhaltet die Verwendung von daemontools . Der Rest des Beitrags beschreibt, wie Sie Dienste mit daemontools einrichten.

Ersteinrichtung

  1. Folgen Sie den Anweisungen in So installieren Sie daemontools . Einige Distributionen (z. B. Debian, Ubuntu) haben bereits Pakete dafür, verwenden Sie diese also einfach.
  2. Erstellen Sie ein Verzeichnis mit dem Namen /service. Das Installationsprogramm sollte dies bereits getan haben, es muss jedoch nur überprüft oder manuell installiert werden. Wenn Sie diesen Speicherort nicht mögen, können Sie ihn in Ihrem svscanboot-Skript ändern, obwohl die meisten daemontools-Benutzer /service verwenden und verwirrt sind, wenn Sie ihn nicht verwenden.
  3. Wenn Sie Ubuntu oder eine andere Distribution verwenden, die nicht den Standard init verwendet (d. H. Nicht /etc/inittab), müssen Sie den vorinstallierten inittab als Basis für das Anordnen von svscanboot verwenden, um von init aufgerufen zu werden. Es ist nicht schwer, aber Sie müssen wissen, wie Sie das von Ihrem Betriebssystem verwendete init konfigurieren. svscanboot ist ein Skript, das svscan aufruft und die Hauptarbeit für die Suche nach Diensten leistet. Es wird von init aufgerufen, sodass init veranlasst, es neu zu starten, wenn es aus irgendeinem Grund abstirbt.

Service-Setup

  1. Jeder Dienst benötigt ein Dienstverzeichnis , in dem die Housekeeping-Informationen zum Dienst gespeichert sind. Sie können auch einen Speicherort für diese Dienstverzeichnisse festlegen, damit sie alle an einem Ort gespeichert werden. Normalerweise verwende ich /var/lib/svscan, aber jeder neue Ort ist in Ordnung.
  2. Normalerweise verwende ich ein Skript , um das Dienstverzeichnis einzurichten und viele manuelle Wiederholungsarbeiten zu sparen. z.B.,

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

    dabei ist some-service-name der Name, den Sie Ihrem Dienst geben möchten, user der Benutzer, unter dem dieser Dienst ausgeführt werden soll, und loguser der Benutzer, unter dem der Logger ausgeführt werden soll. (Die Protokollierung wird kurz erklärt.)

  3. Ihr Dienst muss im Vordergrund laufen . Wenn Ihr Programm standardmäßig einen Hintergrund hat, aber eine Option zum Deaktivieren hat, dann tun Sie dies. Wenn Ihre Programmhintergründe nicht deaktiviert werden können, lesen Sie fghack , obwohl dies einen Kompromiss darstellt: Sie können das Programm nicht mehr mit svc steuern.
  4. Bearbeiten Sie das Skript run, um sicherzustellen, dass es das tut, was Sie möchten. Möglicherweise müssen Sie oben einen sleep-Anruf tätigen, wenn Sie erwarten, dass Ihr Dienst häufig beendet wird.
  5. Wenn alles richtig eingerichtet ist, erstellen Sie in /service einen Symlink, der auf Ihr Dienstverzeichnis verweist. (Platzieren Sie Service-Verzeichnisse nicht direkt in /service. Es erschwert das Entfernen des Service von der Watch von svscan.)

Protokollierung

  1. Die Protokollierungsmethode von daemontools besteht darin, dass der Dienst Protokollnachrichten in die Standardausgabe schreibt (oder einen Standardfehler, wenn Sie mit mkservice generierte Skripts verwenden). svscan kümmert sich um das Senden von Protokollnachrichten an den Protokollierungsdienst.
  2. Der Protokollierungsdienst entnimmt die Protokollnachrichten der Standardeingabe. Das von mkservice generierte Protokolldienstskript erstellt automatisch rotierte Protokolldateien mit Zeitstempel im Verzeichnis log/main. Die aktuelle Protokolldatei heißt current.
  3. Der Protokollierungsdienst kann unabhängig vom Hauptdienst gestartet und gestoppt werden.
  4. Das Weiterleiten der Protokolldateien durch tai64nlocal übersetzt die Zeitstempel in ein für Menschen lesbares Format. (TAI64N ist ein 64-Bit-Atomzeitstempel mit einer Nanosekundenanzahl.)

Controlling-Dienstleistungen

  1. Verwenden Sie svstat , um den Status eines Dienstes abzurufen. Beachten Sie, dass der Protokollierungsdienst unabhängig ist und einen eigenen Status hat.
  2. Sie steuern Ihren Dienst (Starten, Beenden, Neustarten usw.) mit svc . Verwenden Sie beispielsweise svc -t /service/some-service-name, um den Dienst neu zu starten. -t bedeutet "send SIGTERM".
  3. Andere verfügbare Signale sind -h (SIGHUP), -a (SIGALRM), -1 (SIGUSR1), -2 (SIGUSR2) und -k (SIGKILL).
  4. Verwenden Sie zum Herunterfahren des Dienstes -d. Sie können auch verhindern, dass ein Dienst beim Booten automatisch gestartet wird, indem Sie eine Datei mit dem Namen down im Dienstverzeichnis erstellen.
  5. Verwenden Sie zum Starten des Dienstes -u. Dies ist nicht erforderlich, es sei denn, Sie haben es zuvor heruntergefahren (oder es so eingerichtet, dass es nicht automatisch startet).
  6. Verwenden Sie -x, um den Supervisor zum Beenden aufzufordern. Wird normalerweise mit -d verwendet, um den Dienst ebenfalls zu beenden. Dies ist die übliche Methode, um das Entfernen eines Dienstes zuzulassen. Sie müssen jedoch zuerst die Verknüpfung des Dienstes mit /service aufheben, da svscan sonst den Supervisor neu startet. Wenn Sie Ihren Dienst mit einem Protokollierungsdienst (mkservice -l) erstellt haben, müssen Sie auch den Protokollierungs-Supervisor (z. B. svc -dx /var/lib/svscan/some-service-name/log) beenden, bevor Sie das Dienstverzeichnis entfernen.

Zusammenfassung

Vorteile:

  1. daemontools bietet eine umfassende Möglichkeit zum Erstellen und Verwalten von Diensten. Ich verwende es für meine Server und kann es nur empfehlen.
  2. Das Protokollierungssystem ist sehr robust, ebenso wie die Funktion zum automatischen Neustart des Dienstes.
  3. Da Dienste mit einem Shell-Skript gestartet werden, das Sie schreiben/optimieren, können Sie Ihren Dienst nach Ihren Wünschen anpassen.
  4. Leistungsstarke Dienststeuerungstools: Sie können fast jedes Signal an einen Dienst senden und Dienste zuverlässig hoch- und herunterfahren.
  5. Ihren Services wird eine saubere Ausführungsumgebung garantiert: Sie werden mit derselben Umgebung, denselben Prozessbeschränkungen usw. ausgeführt, wie sie init bereitstellt.

Nachteile:

  1. Jeder Dienst benötigt ein wenig Setup. Zum Glück muss dies nur einmal pro Service erledigt werden.
  2. Services müssen so eingerichtet sein, dass sie im Vordergrund ausgeführt werden. Um optimale Ergebnisse zu erzielen, sollten sie auch so eingerichtet werden, dass sie auf Standardausgabe/Standardfehler und nicht auf Syslog oder andere Dateien protokollieren.
  3. Eine steile Lernkurve, wenn Sie mit der Arbeitsweise von daemontools noch nicht vertraut sind. Sie müssen die Dienste mit svc neu starten und können die Ausführungsskripten nicht direkt ausführen (da sie dann nicht unter der Kontrolle des Supervisors stehen würden).
  4. Viele Housekeeping-Dateien und viele Housekeeping-Prozesse. Jeder Dienst benötigt ein eigenes Dienstverzeichnis, und jeder Dienst verwendet einen Supervisor-Prozess, um den Dienst automatisch neu zu starten, wenn er abstürzt. (Wenn Sie viele Services haben, sehen Sie viele supervise -Prozesse in Ihrer Prozesstabelle.)

Alles in allem denke ich, dass daemontools ein exzellentes System für Ihre Bedürfnisse ist. Ich freue mich über alle Fragen zur Einrichtung und Wartung.

32

Sie sollten einen Blick auf daemonize werfen. Ermöglicht die Erkennung einer zweiten Kopie (verwendet jedoch den Dateisperrmechanismus). Es funktioniert auch auf verschiedenen UNIX- und Linux-Distributionen.

Wenn Sie Ihre Anwendung automatisch als Daemon starten müssen, müssen Sie das entsprechende Init-Skript erstellen.

Sie können folgende Vorlage verwenden:

#!/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
12
uthark

Ich denke, Sie möchten vielleicht start-stop-daemon(8) versuchen. Überprüfen Sie die Skripte in /etc/init.d in einer beliebigen Linux-Distribution nach Beispielen. Es kann gestartete Prozesse über die Befehlszeile oder die PID-Datei finden. Daher erfüllt es alle Anforderungen, außer dass es ein Watchdog für Ihr Skript ist. Sie können jedoch jederzeit ein anderes Daemon-Watchdog-Skript starten, das Ihr Skript bei Bedarf einfach neu startet.

11
Alex B

Als Alternative zu den bereits erwähnten Variablen daemonize und daemontools gibt es den Befehl daemon des libslack-Pakets.

daemon ist ziemlich konfigurierbar und kümmert sich um all die langweiligen Daemon-Sachen wie automatischer Neustart, Protokollierung oder Pidfile-Behandlung.

7
jefz

Wenn Sie speziell OS X verwenden, sollten Sie sich die Funktionsweise von launchd ansehen. Es prüft automatisch, ob das Skript ausgeführt wird, und startet es gegebenenfalls erneut. Es enthält auch alle möglichen Planungsfunktionen usw. Es sollte sowohl die Anforderungen 1 als auch 2 erfüllen. 

Um sicherzustellen, dass nur eine Kopie Ihres Skripts ausgeführt werden kann, müssen Sie eine PID-Datei verwenden. Im Allgemeinen schreibe ich eine Datei in /var/run/.pid, die eine PID der aktuell ausgeführten Instanz enthält. Wenn die Datei beim Ausführen des Programms vorhanden ist, wird geprüft, ob die PID in der Datei tatsächlich ausgeführt wird (das Programm ist möglicherweise abgestürzt oder hat sonst vergessen, die PID-Datei zu löschen). Wenn ja, abbrechen. Wenn nicht, starten Sie die Ausführung und überschreiben Sie die PID-Datei.

5
Kamil Kisiel

Daemontools ( http://cr.yp.to/daemontools.html ) ist ein Satz ziemlich harter Kern-Utilities, die dazu verwendet werden. Ich habe das mit einigem Erfolg genutzt. Das Ärgerliche daran ist, dass keines der Skripts sichtbare Ergebnisse liefert, wenn Sie sie ausführen - nur unsichtbare Rückkehrcodes. Aber sobald es läuft, ist es kugelsicher.

5

Holen Sie sich zuerst createDaemon() von http://code.activestate.com/recipes/278731/

Dann der Hauptcode:

import subprocess
import time

createDaemon()

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

Sie können auch Monit versuchen. Monit ist ein Dienst, der andere Dienste überwacht und berichtet. Es wird hauptsächlich als Benachrichtigungsmethode (per E-Mail und SMS) über Laufzeitprobleme verwendet, kann jedoch auch das tun, was die meisten anderen Vorschläge hier befürwortet haben. Es kann Programme automatisch (erneut) starten und stoppen, E-Mails senden, andere Skripts initiieren und ein Protokoll der Ausgabe führen, das Sie abrufen können. Außerdem habe ich festgestellt, dass es einfach zu installieren und zu warten ist, da es eine solide Dokumentation gibt.

1
Adestin

Dies ist eine funktionierende Version mit einem Beispiel, das Sie in ein leeres Verzeichnis kopieren und ausprobieren können (nachdem Sie die CPAN-Abhängigkeiten installiert haben: Getopt :: Long , File :: Spec , File :: Pid und IPC :: System :: Simple - alles ziemlich standardisiert und für jeden Hacker sehr zu empfehlen: Sie können sie alle mit cpan <modulename> <modulename> ... auf einmal installieren.


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";

Nun können Sie das obige Beispiel mit: ./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3 aufrufen, und die Datei pidfile wird erstellt, und Sie sehen die Ausgabe:

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

Sie könnten versuchen, immortal es ist ein * nix-plattformübergreifender (OS-agnostischer) Supervisor. 

Für einen schnellen Versuch mit macOS:

brew install immortal

Falls Sie FreeBSD von den Ports oder von pkg verwenden:

pkg install immortal

Für Linux durch Herunterladen der vorkompilierten Binärdateien oder aus der Quelle: https://immortal.run/source/

Sie können es entweder so verwenden:

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

Oder über eine configuration YAML -Datei, die Ihnen mehr Optionen gibt, zum Beispiel:

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

Wenn Sie auch die Standardfehlerausgabe in einer separaten Datei behalten möchten, können Sie Folgendes verwenden:

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
1
nbari

Ich habe eine Reihe von Verbesserungen an der anderen Antwort vorgenommen.

  1. stdout aus diesem Skript besteht ausschließlich aus stdout, das von seinem untergeordneten Element kommt, WENN es nicht beendet wird, weil erkannt wird, dass der Befehl bereits ausgeführt wird
  2. bereinigt nach dem Beenden der PID-Datei
  3. optional konfigurierbare Timeout-Periode (Akzeptiert alle positiven numerischen Argumente, sendet an sleep)
  4. eingabeaufforderung bei -h
  5. willkürliche Befehlsausführung statt Einzelbefehlsausführung. Die letzten Argumente OR, die noch übrig sind (falls mehr als ein letztes Argument vorhanden ist), werden an eval gesendet. Sie können also jede Art von Shell-Skript als String erstellen, das als letztes Argument (oder nachstehende Argumente) an dieses Skript gesendet wird ) für die Daemonisierung
  6. vergleiche von Argumenten mit -lt anstelle von <

Hier ist das Skript: 

#!/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 "[email protected]"
    echo "I am $$ and my child has exited; restart in ${TIMEOUT}s" >&2
    sleep $TIMEOUT
done

Verwendungszweck: 

$ 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

Beachten Sie, dass beim Ausführen dieses Skripts aus verschiedenen Verzeichnissen möglicherweise andere PID-Dateien verwendet werden und keine vorhandenen Instanzen erkannt werden. Da es für das Ausführen und Neustarten von ephemeren Befehlen, die über ein Argument bereitgestellt werden, entwickelt wurde, gibt es keine Möglichkeit zu wissen, ob bereits etwas gestartet wurde, denn wer sagt, ob es sich um den gleichen Befehl handelt oder nicht? Um diese Durchsetzung zu verbessern, indem nur eine einzige Instanz von etwas ausgeführt wird, ist eine situationsspezifische Lösung erforderlich.

Damit er als richtiger Dämon fungieren kann, müssen Sie (mindestens) Nohup verwenden, wie in der anderen Antwort erwähnt. Ich habe mich nicht bemüht, den Signalen, die der Prozess möglicherweise empfängt, Nachgiebigkeit zu verleihen. 

Ein weiterer wichtiger Punkt ist, dass das Töten dieses Skripts (wenn es von einem anderen Skript, das getötet wird, oder mit einem Signal aufgerufen wird) möglicherweise nicht erfolgreich ist, um das Kind zu töten, insbesondere wenn das Kind noch ein anderes -Skript ist . Ich bin mir nicht sicher, warum dies so ist, aber es scheint etwas zu sein, was eval funktioniert, was für mich geheimnisvoll ist. Daher kann es ratsam sein, diese Zeile durch etwas zu ersetzen, das nur einen einzigen Befehl wie in der anderen Antwort akzeptiert.

0
Steven Lu