Як я демонізую довільний сценарій в unix?


93

Я хотів би демонізатор, який може перетворити довільний загальний сценарій або команду на демон .

Є два поширені випадки, з якими я хотів би розглянути:

  1. У мене є сценарій, який повинен працювати вічно. Якщо він коли-небудь загине (або при перезавантаженні), перезапустіть його. Не дозволяйте виконувати дві копії одночасно (виявіть, чи копія вже запущена, і не запускайте її в такому випадку).

  2. У мене є простий сценарій або команда командного рядка, яку я хотів би продовжувати виконувати неодноразово назавжди (з короткою паузою між запусками). Знову ж таки, не дозволяйте запускати дві копії сценарію одночасно.

Звичайно, тривіально написати цикл "while (true)" навколо сценарію у випадку 2, а потім застосувати рішення для випадку 1, але більш загальне рішення просто вирішить випадок 2 безпосередньо, оскільки це стосується сценарію у випадку 1 як добре (ви можете просто хочете коротше чи ні паузи , якщо сценарій не призначений коли - або померти (звичайно , якщо сценарій дійсно робить не помре , то пауза робить на насправді не має значення)).

Зауважте, що рішення не повинно передбачати, скажімо, додавання коду блокування файлів або запису PID до існуючих сценаріїв.

Більш конкретно, я хотів би програму "демонізувати", яку я можу запускати

% daemonize myscript arg1 arg2

або, наприклад,

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

який міг би зберігати зростаючий список дат, доданих до times.txt. (Зверніть увагу, що якщо аргументи для демонізації - це скрипт, який працює вічно, як у випадку 1 вище, тоді демонізація все одно зробить все правильно, перезапустивши її за необхідності.) Потім я міг би поставити команду, подібну вище, у своєму .login та / або cron щогодини чи щохвилини (залежно від того, наскільки я переживав, що це несподівано помер)

Примітка. Сценарію демонізації потрібно запам'ятати командний рядок, який він демонізує, щоб, якщо той самий командний рядок буде демонізований знову, він не запускав другу копію.

Крім того, рішення в ідеалі має працювати як на OS X, так і на Linux, але вітаються рішення для одного чи іншого.

EDIT: Чудово, якщо вам доведеться це викликати sudo daemonize myscript myargs.

(Якщо я думаю про все це неправильно або є швидкі і брудні часткові рішення, я б також хотів це почути.)


PS: Якщо це корисно, ось подібне запитання, яке стосується python.

І ця відповідь на подібне запитання має, мабуть, корисну ідіому для швидкої та брудної демонізації довільного сценарію:


1
Дивіться serverfault.com/questions/311593/… щодо чистої оболонки
w00t

Відповіді:


90

Ви можете демонізувати будь-який виконуваний файл в Unix, використовуючи nohup та оператор &:

nohup yourScript.sh script args&

Команда nohup дозволяє вам вимкнути сеанс оболонки, не вбиваючи скрипт, тоді як & розміщує скрипт у фоновому режимі, щоб ви отримали підказку оболонки для продовження сеансу. Єдиною незначною проблемою цього є стандартний вихід і стандартна помилка надсилаються на ./nohup.out, тому, якщо ви запустите кілька сценаріїв у цій садибі, їх вихідні дані будуть переплетені. Кращою командою буде:

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

Це надішле стандартний файл до вибраного вами файлу, а стандартна помилка - до іншого файлу на ваш вибір. Якщо ви хочете використовувати лише один файл як для стандартної помилки, так і для стандартної помилки, ви можете використати це:

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

2> & 1 повідомляє оболонці перенаправити стандартну помилку (дескриптор файлу 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 &

Приголомшливо; спасибі. Цікаво, чи має він також мати можливість затримки перезапуску. Або , може бути , краще просто використовувати його в поєднанні з цим: stackoverflow.com/questions/555116 / ...
dreeves

4
Це обробляє лише SIGHUP, є й інші (зазвичай) фатальні сигнали, які слід обробляти.
Tim Post

Ще один спосіб покращити цей сценарій - це, мабуть, придумати йому гарне місце для розміщення $ PIDFILE самостійно, а не вимагати, щоб його вказували як аргумент. Це навіть не прибирає за собою! (що має бути прямолінійно з a trap EXIT)
Стівен Лу

Крім того, враховуйте, що використання <в testє порівнянням ASCII, а не цілим порівнянням. Це все ще може працювати, але може призвести до помилок.
Стівен Лу

Я відправив свої виправлення в цей сценарій тут .
Steven Lu

34

Прошу вибачення за довгу відповідь (будь ласка, перегляньте коментарі про те, як моя відповідь враховує специфікацію). Я намагаюся бути всебічним, щоб у вас було якомога краще піднятої ноги. :-)

Якщо ви можете встановити програми (мати root-доступ) і готові зробити одноразову роботу, щоб налаштувати свій сценарій для виконання демона (тобто, більше задіяний, ніж просто вказівка ​​аргументів командного рядка для запуску в командному рядку, але це потрібно зробити лише один раз за послугу), у мене є спосіб, який є більш надійним.

Це передбачає використання демонтолу . Решта публікації описує, як налаштувати служби за допомогою daemontools.

Початкове налаштування

  1. Дотримуйтесь інструкцій у розділі Як встановити daemontools . Деякі дистрибутиви (наприклад, Debian, Ubuntu) вже мають пакети для нього, тому просто використовуйте це.
  2. Зробіть каталог під назвою /service. Інсталятор повинен був це вже зробити, але просто перевірити, або якщо встановлювати вручну. Якщо вам не подобається це місце, ви можете змінити його у своєму svscanbootсценарії, хоча більшість користувачів daemontools звикли використовувати, /serviceі вони заплутаються, якщо ви ним не користуєтеся.
  3. Якщо ви використовуєте Ubuntu або інший дистрибутив, який не використовує стандартну init(тобто не використовує /etc/inittab), вам потрібно буде використовувати попередньо встановленуinittab в якості основи для організації , svscanbootщоб його називали init. Це не важко, але ви повинні знати, як налаштувати те, initщо використовує ваша ОС. svscanbootце скрипт, який дзвонить svscan, який виконує основну роботу з пошуку служб; його викликають, initтому initдомовляться про його перезапуск, якщо він з якої-небудь причини загине.

Налаштування для кожної послуги

  1. Кожній службі потрібен каталог послуг , який зберігає інформацію про ведення домашнього господарства про послугу. Ви також можете створити місце для розміщення цих каталогів послуг, щоб вони були всі в одному місці; зазвичай я використовую /var/lib/svscan, але будь-яке нове місце буде добре.
  2. Зазвичай я використовую сценарій для налаштування каталогу служб, щоб заощадити багато ручної роботи, що повторюється. наприклад,

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

    де some-service-name ім'я, якому ви хочете дати свою послугу, userє користувачем, який запускає цю послугу як, і loguserкористувачем, який запускає реєстратор як. (Запис журналу пояснюється лише трохи.)

  3. Ваша служба повинна працювати на передньому плані . Якщо фони вашої програми за замовчуванням, але мають можливість вимкнути це, зробіть це. Якщо фони вашої програми не мають можливості її відключити, читайте далі fghack, хоча це призводить до компромісу: ви більше не можете керувати програмою за допомогою svc.
  4. Відредагуйте runсценарій, щоб переконатися, що він робить те, що ви хочете. Можливо, вам доведеться sleepзателефонувати зверху, якщо ви очікуєте, що ваша послуга буде часто виходити.
  5. Коли все налаштовано правильно, створіть символічне посилання, /serviceвказуючи на ваш каталог послуг. (Не розміщуйте каталоги послуг безпосередньо всередині /service; це ускладнює видалення служби зsvscan годинника.)

Лісозаготівля

  1. Спосіб ведення журналу daemontools полягає в тому, щоб служба записувала журнальні повідомлення у стандартний вивід (або стандартну помилку, якщо ви використовуєте сценарії, згенеровані за допомогою mkservice ); svscanдбає про надсилання журнальних повідомлень до служби реєстрації.
  2. Послуга реєстрації журналів приймає повідомлення журналу із стандартного вводу. Сценарій служби ведення журналу, створений, mkserviceстворить автоматично поворотні файли журналів із позначкою часуlog/main каталозі . Викликається поточний файл журналу current.
  3. Послугу лісозаготівля можна запускати та зупиняти незалежно від основної служби.
  4. Проведення файлів журналів tai64nlocal переведе позначки часу в зручний для читання формат. (TAI64N - це 64-розрядна атомна мітка часу з наносекундним відліком.)

Послуги контролінгу

  1. Використовуйте svstat для отримання статусу послуги. Зауважте, що служба реєстрації є незалежною і має власний статус.
  2. Ви керуєте своєю службою (запуск, зупинка, перезапуск тощо) за допомогою svc. Наприклад, щоб перезапустити вашу послугу, використовуйте svc -t /service/some-service-name;-tозначає "відправити SIGTERM".
  3. Інші доступні сигнали включають -h( SIGHUP), -a( SIGALRM), -1( SIGUSR1), -2( SIGUSR2) та -k( SIGKILL).
  4. Щоб заблокувати послугу, скористайтеся -d. Ви також можете запобігти автоматичному запуску служби під час завантаження, створивши файл, названий downу каталозі служби.
  5. Щоб запустити послугу, скористайтеся -u. Це не потрібно, якщо ви раніше не звалили (або не налаштували автоматичний запуск).
  6. Щоб попросити керівника вийти, використовуйте -x; як правило, використовується також -dдля припинення послуги. Це звичайний спосіб дозволити видалення служби, але вам доведеться від’єднати службу від /serviceпершої, інакше svscanперезапустить супервізор. Крім того, якщо ви створили свою службу за допомогою служби ведення журналу ( mkservice -l), не забудьте також вийти з нагляду за веденням журналу (наприклад, svc -dx /var/lib/svscan/some-service-name/log) перед тим, як видалити каталог служби.

Резюме

Плюси:

  1. daemontools забезпечує надійний спосіб створення та управління послугами. Я використовую його для своїх серверів і настійно рекомендую.
  2. Його система реєстрації дуже надійна, як і функція автоматичного перезапуску служби.
  3. Оскільки сервіси запускаються із сценарію оболонки, який ви пишете / налаштовуєте, ви можете налаштувати свою службу як завгодно.
  4. Потужні інструменти управління послугами: ви можете надсилати сервісу більшість будь-яких сигналів і можете надійно переміщувати служби вгору та вниз.
  5. Вашим послугам гарантується чисте середовище виконання: вони будуть виконуватися з тим самим середовищем, обмеженнями процесів тощо, як і те, що initпередбачено.

Мінуси:

  1. Кожна послуга вимагає трохи налаштування. На щастя, це потрібно робити лише один раз за послугу.
  2. Послуги повинні бути налаштовані для роботи на передньому плані. Крім того, для досягнення найкращих результатів їх слід налаштовувати на реєстрацію до стандартного виводу / стандартної помилки, а не до системного журналу чи інших файлів.
  3. Крута крива навчання, якщо ви новачок у способах роботи daemontools. Вам доведеться перезапустити служби за допомогоюsvc , і не можете запускати сценарії запуску безпосередньо (оскільки вони тоді не будуть під контролем супервізора).
  4. Багато файлів ведення домашнього господарства та багато процесів ведення домашнього господарства. Кожна служба потребує власного каталогу служб, і кожна служба використовує один процес нагляду, щоб автоматично перезапустити службу, якщо вона загине. (Якщо у вас багато послуг, ви побачите багато з superviseпроцесів у вашій таблиці процесів.)

В балансі, я думаю, daemontools - це відмінна система для ваших потреб. Я вітаю будь-які запитання щодо того, як його налаштувати та підтримувати.


Як моя відповідь враховує специфікацію: 1. Ви повинні налаштувати служби, тому, доки ви не налаштуєте дублікати (і поки ваша служба не виконує фоновий режим), дублікатів не буде. 2. supervise, керівник, дбає про перезапуск будь-якої служби, яка виходить. Він чекає однієї секунди між перезапусками; якщо для вас недостатньо часу, увімкніть режим сну у верхній частині сценарію запуску служби.
Chris Jester-Young

2а. superviseсам підтримується svscan, тому, якщо керівник помер, його буде перезапущено. 2б. svscanпідтримується init, що автоматично перезапустить svscanза необхідності. 2в. Якщо ти initвмираєш з будь-якої причини, ти все одно збився. :-P
Кріс Джестер-Янг

Щоб відповісти на інші запитання щодо ведення домашнього господарства, система daemontools не використовує файли PID, оскільки вони можуть застаріти. Натомість вся інформація про процес зберігається у керівника, який підтримує певну послугу. Супервайзер зберігає купу файлів (і FIFO) у каталозі сервісів, яким інструменти подобаються svstatі з якими svcможна працювати.
Кріс Джестер-Янг

3
Ми повинні мати більше таких публікацій в SO та в мережі загалом. Не просто рецепт того, як досягти бажаного ефекту, але той, який намагається пояснити рецепти. Чому я не можу проголосувати за це більше одного разу? : |
skytreader

12

Я думаю, ви можете спробувати start-stop-daemon(8). Перегляньте сценарії в /etc/init.dбудь-якому дистрибутиві Linux для прикладів. Він може знаходити запущені процеси за допомогою командного рядка або файлу PID, тому він відповідає усім вашим вимогам, за винятком того, що є сторожем для вашого сценарію. Але ви завжди можете запустити інший скрипт сторожової програми демона, який просто перезапускає ваш сценарій, якщо це необхідно.


У Fedora поки що немає запуску-зупинки-демона, тому сценарії, залежно від нього, не є портативними. Див .: fedoraproject.org/wiki/Features/start-stop-daemon
Бенгт,

Просто підказка для користувачів OSX: start-stop-daemonтам теж немає (станом на 10.9).
mklement0

@ mklement0 Ну ... за майже 5 років багато що змінилося.
Alex B

Мій, як летить час. start-stop-daemonвсе ще живе і працює на Linux; але після прочитання відповіді stackoverflow.com/a/525406/45375 я зрозумів , що OSX робить свою справу: launchd.
mklement0

12

Ви повинні поглянути на демонізацію . Це дозволяє виявити другу копію (але вона використовує механізм блокування файлів). Також він працює на різних дистрибутивах UNIX та Linux.

Якщо вам потрібно автоматично запустити програму як демон, вам потрібно створити відповідний скрипт ініціювання.

Ви можете використовувати такий шаблон:

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

1
Виглядає кандидатом на правильну відповідь. Особливо враховуючи його "перевірку одного екземпляра".
Мартін Вікман,

Це може бути найкраща можлива відповідь - я не впевнений - але якщо ви вважаєте, що так, чи можете ви також включити пояснення, чому специфікація, яку я дав у запитанні, є неправильною?
dreeves

Мені не подобається killprocчастина зупинки: якщо у вас був процес, який, скажімо, був запущений java, це killprocпризведе до того, що всі інші процеси Java також будуть вбиті.
Chris Jester-Young

1
З /etc/rc.d/init.d/functions, daemonize просто запускає двійковий файл з нової оболонки: $ cgroup $ nice / bin / bash -c $corelimit >/dev/null 2>&1 ; $*Тож я сумніваюся, що це щось
демонізує

1
Я знаю, що це старе, але для тих, хто знайде це пізніше ... це правильно. "демон", як визначено в /etc/init.d/functions, насправді не демонізує для вас. Це просто обгортка, щоб робити cgroups, перевіряти, чи вже запущений процес, встановлювати користувача, встановлювати приємні та обмежені значення тощо. Це не демонізує процес для вас. Це все-таки ваша власна робота. :)
jakem

7

Як альтернатива вже згаданому daemonizeі daemontools, існує команда демона пакета libslack.

daemon цілком налаштовується і дбає про всі нудні демони, такі як автоматичний перезапуск, реєстрація або обробка pidfile.


5

Якщо ви спеціально використовуєте OS X, я пропоную вам поглянути, як працює launchd. Він автоматично перевірить, чи працює ваш скрипт, і за потреби перезапустить його. Він також включає всілякі функції планування тощо. Він повинен відповідати вимогам 1 і 2.

Що стосується забезпечення лише однієї копії вашого сценарію, вам потрібно використовувати файл PID. Як правило, я пишу файл /var/run/.pid, який містить PID поточного запущеного екземпляра. якщо файл існує під час запуску програми, він перевіряє, чи дійсно працює PID у файлі (можливо, програма аварійно завершила роботу або забула видалити файл PID). Якщо це так, перервати. Якщо ні, запустіть і перезапишіть файл PID.


5

Daemontools ( http://cr.yp.to/daemontools.html ) - це набір досить жорстких службових програм, які використовувались для цього, написані ді-джеєм Бернштейном. Я використовував це з певним успіхом. Прикро в цьому полягає те, що жоден із сценаріїв не повертає видимих ​​результатів під час їх запуску - лише невидимі коди повернення. Але після запуску він стає куленепробивним.


Так, я збирався написати запис, який теж використовує daemontools. Я напишу свій власний пост, тому що я сподіваюся бути набагато вичерпнішим зі своєю відповіддю, і сподіваюся отримати щедрість таким чином. Побачимо. :-)
Кріс Джестер-Янг

3

Спершу отримати createDaemon()з http://code.activestate.com/recipes/278731/

Тоді основний код:

import subprocess
import sys
import time

createDaemon()

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

Ой, дякую! Хочете зробити це трохи загальнішим, щоб ви могли зробити "демонізувати foo arg1 arg2", а також "демонізувати 'foo arg1 arg2'"?
dreeves

Гаразд, це об’єднає аргументи зараз - однак вам доведеться його змінити, якщо ви коли-небудь захочете мати пробіли в аргументах.
Дуглас Лідер,

Дякую Дугласу! Однак є великий недолік: запуск "daemonize foo" двічі запускає дві копії запуску foo.
dreeves

Ви можете додати якийсь код запису PID, але, можливо, найкраще запустити сценарій лише один раз ...
Дуглас Лідер,

Я думаю, що це є фундаментальним для всієї концепції обгортки "демонізувати". (Наприклад, я міг би це потім поговорити щогодини чи щохвилини, щоб переконатися, що воно завжди працює.) Я думаю про це неправильно? Чи вже CreatDaemon це якось гарантує? А як щодо перезавантаження?
сітки

1

Це робоча версія з прикладом, який ви можете скопіювати в порожній каталог і спробувати (після встановлення залежностей CPAN, таких як Getopt :: Long , File :: Spec , File :: Pid та IPC :: System: : Простий - все досить стандартне і настійно рекомендується будь-якому хакеру: ви можете встановити їх усі одночасно за допомогою 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";

Тепер ви можете викликати наведений вище приклад за допомогою: ./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

@dreeves: так, але є два шляхи: 1. скрипт, який викликається keepAlive.pl (наприклад, example.pl), може бути просто обгорткою для виконання реальної програми, або 2. keepAlive.pl може проаналізувати таблицю активні системні процеси (за допомогою Proc :: ProcessTable CPAN) для спроби знайти відповідний процес та його pid).
Ether

1

Ви також можете спробувати Monit . Monit - це служба, яка здійснює моніторинг та звітування про інші послуги. Хоча він в основному використовується як спосіб сповіщення (електронною поштою та смс) про проблеми під час виконання, він також може робити те, що пропонується більшістю інших пропонованих тут пропозицій. Він може автоматично (повторно) запускати та зупиняти програми, надсилати електронні листи, ініціювати інші сценарії та вести журнал вихідних даних, який ви можете забрати. Крім того, я виявив, що його легко встановити та обслуговувати, оскільки існує солідна документація.


1

Ви можете спробувати безсмертний Це крос-платформенний (агностичний ОС) керівник * nix.

Щоб швидко спробувати macOS:

brew install immortal

Якщо ви використовуєте FreeBSD з портів або за допомогою pkg:

pkg install immortal

Для Linux , завантаживши скомпільовані двійкові файли або з джерела: https://immortal.run/source/

Ви можете використовувати його так:

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

Або конфігураційним файлом 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

0

Я вніс ряд вдосконалень щодо іншої відповіді .

  1. stdout з цього скрипта суто складається зі stdout, що надходить від його дочірньої організації, якщо він не вийде через виявлення того, що команда вже запущена
  2. очищається після його pidfile при припиненні
  3. необов’язковий настроюваний період очікування (приймає будь-який позитивний числовий аргумент, надсилає до sleep)
  4. підказку про використання на -h
  5. довільне виконання команди, а не виконання однієї команди. Надіслано останній аргумент АБО що залишився аргумент (якщо більше одного останнього аргументу) eval, тому ви можете створити будь-який сценарій оболонки як рядок, який слід надіслати цьому сценарію як останній аргумент (або кінцеві аргументи) для демонізації.
  6. аргументи підрахування порівнянь, виконаних -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 ${TIMEOUT}s" >&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

Пам'ятайте, що якщо ви запускаєте цей сценарій з різних каталогів, він може використовувати різні файли pid і не виявляти жодних запущених екземплярів. Оскільки він призначений для запуску та перезапуску ефемерних команд, наданих через аргумент, неможливо дізнатися, чи щось вже запущено, бо хто скаже, чи це та сама команда чи ні? Щоб покращити це забезпечення лише запуску одного екземпляра чогось, потрібне рішення, специфічне для ситуації.

Крім того, щоб він функціонував як належний демон, ви повинні використовувати (як мінімум) nohup, як згадується в інших відповідях. Я не докладав зусиль, щоб забезпечити стійкість до сигналів, які може отримати процес.

Ще один момент, на який слід звернути увагу, полягає в тому, що вбивство цього сценарію (якщо його було викликано з іншого скрипта, який був убитий, або з сигналом) може не призвести до вбивства дитини, особливо якщо дитина є ще одним сценарієм. Я не впевнений, чому це так, але, здається, це щось пов’язане із способом evalроботи, який для мене загадковий. Тож може бути доцільним замінити цей рядок чимось, що приймає лише одну команду, як у іншій відповіді.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.