Jak daemonizować dowolny skrypt w Uniksie?

Chciałbym daemonizera, który potrafi zamienić dowolny, ogólny skrypt lub polecenie w daemon .

Są dwa typowe przypadki, którymi chciałbym się zająć:

  1. Mam skrypt, który powinien działać w nieskończoność. Jeśli kiedykolwiek umrze (lub po ponownym uruchomieniu), uruchom go ponownie. Nie pozwól, aby kiedykolwiek działały dwie kopie jednocześnie(Wykryj, czy kopia jest już uruchomiona i nie uruchamiaj jej w takim przypadku).

  2. Mam prosty skrypt lub polecenie linii poleceń, które chciałbym zachować wykonywanie wielokrotnie w nieskończoność(z krótką przerwą między uruchomieniami). Ponownie, nie pozwól, aby dwie kopie skryptu kiedykolwiek były uruchomione na raz.

Oczywiście trywialne jest napisanie pętli "while(true)" wokół skryptu w przypadku 2, a następnie zastosowanie rozwiązania dla Przypadku 1, ale bardziej ogólne rozwiązanie po prostu rozwiąże przypadek 2 bezpośrednio, ponieważ dotyczy to również skryptu w przypadku 1 (możesz chcieć krótszej lub żadnej pauzy, jeśli skrypt nie ma na celu kiedykolwiek umrzeć (oczywiście, jeśli skrypt nie ma na celu kiedykolwiek umrzeć). naprawdę does never die then the pause doesn ' t actually matter)).

Zauważ, że rozwiązanie nie powinno obejmować, powiedzmy, dodawania kodu blokującego pliki lub nagrywania PID do istniejących skryptów.

Dokładniej, chciałbym program "daemonize", który mogę uruchomić jak

% daemonize myscript arg1 arg2

Lub, na przykład,

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

Który utrzymywałby rosnącą listę dat dołączanych do czasów.txt. (Zauważ, że jeśli argument(y) do demonizacji jest skryptem, który działa w nieskończoność jak w przypadku 1 powyżej, to daemonize nadal będzie działać prawidłowo, uruchamiając go ponownie, gdy będzie to konieczne.) Mógłbym wtedy umieścić polecenie jak wyżej w moim .Zaloguj się i / lub cron to co godzinę lub minutely (w zależności od tego, jak martwiłem się o to, że umiera niespodziewanie).

NB: skrypt daemonize będzie musiał zapamiętać ciąg poleceń, który jest demonizowany, tak aby Jeśli ten sam ciąg poleceń jest demonizowany ponownie, nie uruchamia drugiej kopii.

Ponadto rozwiązanie powinno idealnie działać zarówno na OS X, jak i Linuksie, ale rozwiązania dla jednego lub inne są mile widziane.

EDIT: w porządku, jeśli musisz wywołać go za pomocą sudo daemonize myscript myargs.

(jeśli myślę o tym źle lub są szybkie i brudne częściowe rozwiązania, też chciałbym to usłyszeć.)


PS: jeśli jest to przydatne, oto podobne pytanie specyficzne dla Pythona.

I ta odpowiedź na podobne pytanie ma coś, co wydaje się być użytecznym idiomem do szybkiego i brudnego demonizowania dowolnego skryptu:

Author: Community, 2009-02-08

12 answers

Możesz demonizować dowolny plik wykonywalny w Uniksie używając nohup i operatora&:

nohup yourScript.sh script args&

Polecenie nohup pozwala na zamknięcie sesji powłoki bez zabijania skryptu, podczas gdy & umieszcza skrypt w tle, aby uzyskać monit powłoki, aby kontynuować sesję. Jedynym drobnym problemem jest standardowe wyjście i standardowy błąd, do którego są wysyłane.nohup.out, więc jeśli uruchomisz kilka skryptów w tym dworku ich wynik będzie spleciony. Lepsze dowodzenie be:

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

Spowoduje to wysłanie standardowego pliku do wybranego przez Ciebie pliku, a standardowego błędu do innego wybranego przez Ciebie pliku. Jeśli chcesz użyć tylko jednego pliku zarówno dla standardowego wyjścia, jak i standardowego błędu, możesz nam to zrobić:

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

2>&1 mówi powłoce, aby przekierowała błąd standardowy (deskryptor pliku 2) do tego samego pliku co standardowy out (deskryptor pliku 1).

Aby uruchomić polecenie tylko raz i zrestartować je, jeśli umrze, możesz użyć tego skryptu:

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

Pierwszy argument to nazwa używanego pliku pid. Drugim argumentem jest komenda. A wszystkie inne argumenty są argumentami komendy.

Jeśli nazwiesz ten skrypt restart.sh tak byś to nazwał:

nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &
 85
Author: Robert Menteer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-02 15:53:54

Przepraszam za długą odpowiedź (proszę zapoznać się z komentarzami na temat tego, jak moja odpowiedź spełnia wymagania). Staram się być kompleksowy, żebyś miał jak najwięcej siły. :-)

Jeśli jesteś w stanie instalować programy (masz dostęp do roota) i jesteś gotów wykonać jednorazową pracę, aby skonfigurować skrypt do wykonywania demona (tj. bardziej zaangażowany niż po prostu określanie argumentów wiersza poleceń, które mają być uruchomione w wierszu poleceń, ale muszą być wykonane tylko raz na usługę), mam sposób, który może być bardziej wytrzymałe.

Polega na użyciu daemontools . Reszta posta opisuje jak skonfigurować usługi za pomocą daemontools.

Wstępna konfiguracja

    Wykonaj instrukcje w Jak zainstalować daemontools . Niektóre dystrybucje (np. Debian, Ubuntu) mają już pakiety dla niego, więc po prostu użyj tego.
  1. Stwórz katalog o nazwie /service. Instalator powinien już to zrobić, ale wystarczy zweryfikować lub zainstalować ręcznie. Jeśli ci się to nie podoba lokalizacja, możesz ją zmienić w skrypcie svscanboot, chociaż większość użytkowników daemontools jest przyzwyczajona do używania /service i będzie zdezorientowana, jeśli jej nie użyjesz.
  2. jeśli używasz Ubuntu lub innej dystrybucji, która nie używa standardowego init (tzn. nie używa /etc/inittab), będziesz musiał użyć preinstalowanego inittab jako podstawy do organizowania svscanboot do wywołania przez init. Nie jest to trudne, ale musisz wiedzieć, jak skonfigurować init, którego używa Twój system operacyjny. svscanboot jest skryptem wywołującym svscan, który wykonuje główne praca szukania usług; nazywa się to od init, więc init zorganizuje ponowne uruchomienie go, jeśli umrze z jakiegokolwiek powodu.

Konfiguracja usługi

  1. każdy serwis potrzebuje katalog usług , który przechowuje informacje o serwisie. Możesz również zrobić lokalizację do przechowywania tych katalogów usług, aby wszystkie były w jednym miejscu; zwykle używam /var/lib/svscan, ale każda nowa lokalizacja będzie w porządku.
  2. Zwykle używam skryptu , aby skonfigurować katalog usług, aby zapisać wiele ręcznych powtarzalnych prac. np.,

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

    Gdzie some-service-name jest nazwą, którą chcesz nadać swojej usłudze, {[16] } jest użytkownikiem, który uruchomi tę usługę, a loguser jest użytkownikiem, który uruchomi logger jako. (Logowanie jest wyjaśnione tylko trochę.)

  3. Twój serwis musi działać na pierwszym planie . Jeśli twój program domyślnie tła, ale ma opcję, aby wyłączyć, to zrobić. Jeśli twój program nie ma możliwości jego wyłączenia, Czytaj dalej fghack, chociaż jest to kompromis: nie można już kontrolować programu za pomocą svc.
  4. Edytuj skrypt run, aby upewnić się, że robi to, co chcesz. Może być konieczne umieszczenie połączenia sleep na górze, jeśli oczekujesz, że usługa będzie często opuszczana.
  5. gdy wszystko jest dobrze skonfigurowane, Utwórz dowiązanie symboliczne w /service wskazujące na katalog usług. (Nie umieszczaj katalogów usług bezpośrednio w /service; utrudnia to usunięcie usługi z svscan's watch.)

Logowanie

  1. sposób logowania daemontools polega na tym, aby usługa zapisywała komunikaty dziennika na standardowe wyjście (lub standardowy błąd, jeśli używasz skryptów wygenerowanych z mkservice); svscan dba o wysyłanie wiadomości logowania do usługi logowania.
  2. usługa logowania pobiera komunikaty dziennika ze standardowego wejścia. Skrypt usługi logowania wygenerowany przez mkservice utworzy automatycznie obracane pliki dziennika w katalogu log/main. Prąd plik dziennika nazywa się current.
  3. usługa logowania może być uruchamiana i zatrzymywana niezależnie od usługi głównej.
  4. Przepuszczanie plików dziennika przez tai64nlocal przetłumaczy znaczniki czasu na format czytelny dla człowieka. (TAI64N to 64-bitowy Atomic timestamp z liczbą nanosekund.)

Controlling services

  1. użycie svstat aby uzyskać status usługi. Należy pamiętać, że usługa logowania jest niezależna i posiada własne status.
  2. kontrolujesz swoją usługę (start, stop, restart itp.) za pomocą svc. Na przykład, aby ponownie uruchomić usługę, użyj svc -t /service/some-service-name; -t oznacza " wyślij SIGTERM".
  3. inne dostępne sygnały obejmują -h (SIGHUP), -a (SIGALRM), -1 (SIGUSR1), -2 (SIGUSR2), oraz -k (SIGKILL).
  4. aby wyłączyć usługę, użyj -d. Można również zapobiec automatycznemu uruchomieniu usługi podczas rozruchu, tworząc plik o nazwie down w Katalogu usługi.
  5. To uruchom usługę, użyj -u. Nie jest to konieczne, chyba że wcześniej go wyłączyłeś(lub Ustawiłeś, aby nie uruchamiał się automatycznie).
  6. aby poprosić przełożonego o wyjście, użyj -x; zwykle używane z -d również do zakończenia usługi. Jest to zwykły sposób, aby umożliwić usunięcie usługi, ale musisz najpierw odłączyć usługę od /service, albo svscan uruchomi ponownie nadzorcę. Ponadto, jeśli utworzyłeś swoją usługę za pomocą usługi logowania (mkservice -l), pamiętaj, aby również zakończyć logowanie supervisor (np. svc -dx /var/lib/svscan/some-service-name/log) przed usunięciem katalogu usług.

Podsumowanie

Plusy:

  1. daemontools zapewnia kuloodporny sposób tworzenia i zarządzania usługami. Używam go do moich serwerów i Gorąco polecam.
  2. jego system logowania jest bardzo solidny, podobnie jak funkcja automatycznego restartu serwisu.
  3. ponieważ uruchamia usługi ze skryptem powłoki, który piszesz/dostrajasz, możesz dostosować swoją usługę do własnych potrzeb.
  4. potężny serwis narzędzia sterowania: możesz wysłać większość dowolnego sygnału do usługi i niezawodnie wprowadzać usługi w górę iw dół.
  5. Twoje usługi mają zagwarantowane czyste środowisko wykonawcze: będą wykonywane z tym samym środowiskiem, ograniczeniami procesów itp., co zapewnia init.

Wady:

  1. każda usługa wymaga trochę konfiguracji. Na szczęście trzeba to zrobić tylko raz na usługę.
  2. usługi muszą być ustawione tak, aby działały na pierwszym planie. Również, aby uzyskać najlepsze wyniki, powinny być skonfigurowany do logowania do standardowego wyjścia / standardowego błędu, zamiast syslogu lub innych plików.
  3. [69]}stroma krzywa uczenia się, jeśli jesteś nowy w daemontools sposób robienia rzeczy. Trzeba zrestartować usługi używając svc i nie można bezpośrednio uruchomić skryptów run (ponieważ wtedy nie byłyby one pod kontrolą przełożonego). Wiele plików porządkowych i wiele procesów porządkowych. Każda usługa potrzebuje własnego katalogu usług, a każda usługa wykorzystuje jeden proces nadzorcy do auto-restart usługi, jeśli umrze. (Jeśli masz wiele usług, zobaczysz wiele supervise procesów w tabeli procesów.)

W równowadze, myślę, że daemontools jest doskonałym systemem dla Twoich potrzeb. Czekam na wszelkie pytania, jak je skonfigurować i utrzymać.

 31
Author: Chris Jester-Young,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-18 04:57:20

Powinieneś rzucić okiem na daemonize . Pozwala na wykrycie drugiej kopii (ale wykorzystuje mechanizm blokowania plików). Działa również na różnych dystrybucjach UNIX i Linux.

Jeśli chcesz automatycznie uruchomić aplikację jako demon, musisz utworzyć odpowiedni skrypt init.

Możesz użyć następującego szablonu:

#!/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
Author: uthark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 02:52:10

Myślę, że możesz chcieć spróbować start-stop-daemon(8). Sprawdź skrypty w /etc/init.d W dowolnej dystrybucji Linuksa, aby znaleźć przykłady. Może znaleźć rozpoczęte procesy przez wywołany wiersz poleceń lub plik PID, więc spełnia wszystkie twoje wymagania, z wyjątkiem bycia watchdog dla Twojego skryptu. Ale zawsze można uruchomić inny skrypt DAEMON watchdog, który po prostu uruchamia ponownie skrypt, jeśli to konieczne.

 11
Author: Alex B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-09 01:25:44

Jako alternatywa dla wymienionych już daemonize i daemontools, istnieje polecenie daemon pakietu libslack.

daemon jest dość konfigurowalny i dba o wszystkie żmudne rzeczy demona, takie jak automatyczne ponowne uruchamianie, rejestrowanie lub Obsługa plików PID.

 7
Author: jefz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-09 14:46:06

Jeśli używasz OS X konkretnie, proponuję rzucić okiem na działanie launchd. Automatycznie sprawdzi, czy skrypt jest uruchomiony i w razie potrzeby uruchom go ponownie. Zawiera również wszelkiego rodzaju funkcje planowania, itp. Powinien spełniać zarówno wymóg 1, jak i 2.

Aby zapewnić, że tylko jedna kopia skryptu może zostać uruchomiona, musisz użyć pliku PID. Generalnie zapisuję plik do /var / run/.pid, który zawiera PID bieżącej uruchomionej instancji. jeśli plik istnieje, gdy program działa, sprawdza, czy PID w pliku jest rzeczywiście uruchomiony (program mógł się zawiesić lub w inny sposób zapomniał usunąć plik PID). Jeśli tak, przerwij. Jeśli nie, zacznij działać i Nadpisz plik PID.

 5
Author: Kamil Kisiel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-08 08:33:25

Daemontools (http://cr.yp.to/daemontools.html ) jest zestawem dość hard-core narzędzia używane do tego, napisany przez dj bernstein. Użyłem tego z pewnym sukcesem. Irytujące jest to, że żaden ze skryptów nie zwraca widocznych wyników po ich uruchomieniu - po prostu niewidoczne kody zwrotne. Ale po uruchomieniu jest kuloodporny.

 5
Author: fastmultiplication,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-17 05:11:50

Najpierw pobierz createDaemon() z http://code.activestate.com/recipes/278731/

Następnie główny kod:

import subprocess
import time

createDaemon()

while True:
    subprocess.call(" ".join(sys.argv[1:]),shell=True)
    time.sleep(10)
 3
Author: Douglas Leeder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-08 15:37:41

Jest to wersja robocza wraz z przykładem, który możesz skopiować do pustego katalogu i wypróbować (po zainstalowaniu zależności CPAN, które są Getopt:: Long, plik: Spec, File:: Pid , and IPC:: System:: Simple -- all pretty standard and are highly recommended for any hacker: you can install them all at once with cpan <modulename> <modulename> ...).


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

Teraz możesz wywołać powyższy przykład za pomocą: ./keepAlive.pl --pidfile=pidfile --command=./example.pl 1 2 3, A Plik pidfile zostanie utworzony i zobaczysz wyjście:

Pid <random number here> no longer running; restarting ./example.pl 1 2 3
./example.pl got arguments: 1 2 3
 1
Author: Ether,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-08 08:34:06

Możesz również spróbować Monit . Monit to usługa, która monitoruje i raportuje inne usługi. Chociaż jest używany głównie jako sposób powiadamiania (za pośrednictwem poczty e-mail i sms) o problemach związanych z uruchomieniem, może również zrobić to, co zalecało większość innych sugestii. Może automatycznie (ponownie)uruchamiać i zatrzymywać programy, wysyłać wiadomości e-mail, inicjować Inne skrypty i utrzymywać dziennik wyników, które możesz odebrać. Ponadto odkryłem, że jest łatwy w instalacji i utrzymaniu, ponieważ istnieje solidna dokumentacja.

 1
Author: Adestin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 13:51:55

Możesz spróbować immortal jest to * Nix cross-platform (OS) supervisor.

Jeśli nie masz jeszcze konta na macOS]}
brew install immortal

Jeśli używasz FreeBSD z portów lub używając pkg:

pkg install immortal

Dla Linuksa pobierając wstępnie skompilowane binaria lub ze źródła: https://immortal.run / source /

Możesz go użyć w następujący sposób:

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

Lub przez plik konfiguracyjny YAML , który daje więcej opcje, na przykład:

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

Jeśli chcesz zachować również standardowe wyjście błędu w osobnym pliku, możesz użyć czegoś takiego jak:

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
Author: nbari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-07 19:07:14

Wprowadziłem szereg ulepszeń na inna odpowiedź.

  1. stdout z tego skryptu składa się wyłącznie ze stdout pochodzącego z jego potomka, chyba że zakończy się z powodu wykrycia, że komenda jest już uruchomiona
  2. czyści po zakończeniu pidfile
  3. opcjonalny konfigurowalny okres czasu (przyjmuje dowolny dodatni argument liczbowy, wysyła do sleep)
  4. znak zachęty na -h
  5. dowolne wykonywanie poleceń, a nie pojedyncze wykonanie polecenia. Ostatnie arg lub pozostałe args (jeśli więcej niż jedno ostatnie arg) są wysyłane do eval, więc można skonstruować dowolny skrypt powłoki jako ciąg znaków, aby wysłać do tego skryptu jako ostatnie arg (lub końcowe args), aby daemonize
  6. porównywanie liczby argumentów za pomocą -lt zamiast <

Oto skrypt:

#!/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 ${TIMEOUT}s" >&2
    sleep $TIMEOUT
done

Użycie:

$ 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

Uważaj, że jeśli uruchomisz ten skrypt z różnych katalogów, może on używać różnych plików PID i nie wykrywać wszystkie istniejące uruchomione instancje. Ponieważ jest on przeznaczony do uruchamiania i restartowania efemerycznych poleceń dostarczanych przez argument, nie ma sposobu, aby dowiedzieć się, czy coś zostało już uruchomione, bo kto ma powiedzieć, czy jest to ta sama Komenda czy nie? Aby usprawnić egzekwowanie stosowania tylko jednej instancji czegoś, wymagane jest rozwiązanie specyficzne dla danej sytuacji.

Również, aby działał jako właściwy Demon, musisz użyć (minimum) nohup jako drugiego odpowiedź wspomina. Dołożyłem wszelkich starań, aby zapewnić odporność na sygnały, które proces może otrzymać.

Należy jeszcze zwrócić uwagę na to, że zabicie tego skryptu (jeśli został wywołany z innego skryptu, który jest zabity, lub z sygnałem) może nie odnieść sukcesu w zabiciu dziecka, zwłaszcza jeśli dziecko jest kolejnym skryptem {32]}. Nie wiem, dlaczego tak jest, ale wydaje mi się, że jest to coś związanego ze sposobem działania eval, który jest dla mnie tajemniczy. Więc może być rozsądne, aby zastąpić ta linia z czymś, co akceptuje tylko jedno polecenie, jak w drugiej odpowiedzi.

 0
Author: Steven Lu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:38