Мне интересно, есть ли лучший способ создать демона, который ждет чего-то, используя только sh, чем:
#! /bin/sh
trap processUserSig SIGUSR1
processUserSig() {
echo "doing stuff"
}
while true; do
sleep 1000
done
В частности, мне интересно, есть ли способ избавиться от петли и по-прежнему слушать сигналы.
Ответы:
Используйте средство демона вашей системы, например start-stop-daemon .
В противном случае да, где-то должна быть петля.
источник
Простое выполнение вашего скрипта (
./myscript &
) не приведет к его демонизации. См. Http://www.faqs.org/faqs/unix-faq/programmer/faq/ , раздел 1.7, в котором описано, что необходимо, чтобы стать демоном. Вы должны отключить его от терминала, чтобыSIGHUP
не убить его. Вы можете использовать ярлык, чтобы скрипт выглядел как демон;сделаю свою работу. Или, чтобы записать как stderr, так и stdout в файл:
Однако могут быть и другие важные аспекты, которые вам необходимо учитывать. Например:
chdir("/")
(илиcd /
внутри вашего скрипта) выполнить форк, чтобы родительский элемент вышел, и, таким образом, исходный дескриптор был закрыт.umask 0
. Возможно, вы не захотите зависеть от umask вызывающего демона.Для примера сценария , который принимает все эти аспекты во внимание, см ответ Mike S» .
источник
0<&-
делать? Непонятно, что делает эта последовательность символов.0<&-
нужно делать. Я нашел эту ссылку, которая объясняет это.0<&-
закрывает stdin (fd 0). Таким образом, если ваш процесс случайно читает из стандартного ввода (легко сделать), он получит сообщение об ошибке вместо того, чтобы вечно зависать в ожидании появления данных.В некоторых ответах, получивших наибольшее количество голосов, здесь отсутствуют некоторые важные части того, что делает демона демоном, в отличие от просто фонового процесса или фонового процесса, отделенного от оболочки.
Этот http://www.faqs.org/faqs/unix-faq/programmer/faq/ описывает, что необходимо для работы демона. И этот сценарий Run bash as daemon реализует setsid, хотя он пропускает chdir для root.
Вопрос оригинального плаката был на самом деле более конкретным, чем «Как мне создать процесс-демон с помощью bash?», Но поскольку в теме и ответах обсуждаются сценарии демонизации оболочки в целом, я думаю, что важно указать на это (для таких нарушителей, как я, изучающих мелкие детали создания демона).
Вот мой вариант сценария оболочки, который будет вести себя в соответствии с FAQ. Установите DEBUG, чтобы
true
увидеть красивый вывод (но он также завершается немедленно, а не зацикливается бесконечно):#!/bin/bash DEBUG=false # This part is for fun, if you consider shell scripts fun- and I do. trap process_USR1 SIGUSR1 process_USR1() { echo 'Got signal USR1' echo 'Did you notice that the signal was acted upon only after the sleep was done' echo 'in the while loop? Interesting, yes? Yes.' exit 0 } # End of fun. Now on to the business end of things. print_debug() { whatiam="$1"; tty="$2" [[ "$tty" != "not a tty" ]] && { echo "" >$tty echo "$whatiam, PID $$" >$tty ps -o pid,sess,pgid -p $$ >$tty tty >$tty } } me_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" me_FILE=$(basename $0) cd / #### CHILD HERE ---------------------------------------------------------------------> if [ "$1" = "child" ] ; then # 2. We are the child. We need to fork again. shift; tty="$1"; shift $DEBUG && print_debug "*** CHILD, NEW SESSION, NEW PGID" "$tty" umask 0 $me_DIR/$me_FILE XXrefork_daemonXX "$tty" "$@" </dev/null >/dev/null 2>/dev/null & $DEBUG && [[ "$tty" != "not a tty" ]] && echo "CHILD OUT" >$tty exit 0 fi ##### ENTRY POINT HERE --------------------------------------------------------------> if [ "$1" != "XXrefork_daemonXX" ] ; then # 1. This is where the original call starts. tty=$(tty) $DEBUG && print_debug "*** PARENT" "$tty" setsid $me_DIR/$me_FILE child "$tty" "$@" & $DEBUG && [[ "$tty" != "not a tty" ]] && echo "PARENT OUT" >$tty exit 0 fi ##### RUNS AFTER CHILD FORKS (actually, on Linux, clone()s. See strace --------------> # 3. We have been reforked. Go to work. exec >/tmp/outfile exec 2>/tmp/errfile exec 0</dev/null shift; tty="$1"; shift $DEBUG && print_debug "*** DAEMON" "$tty" # The real stuff goes here. To exit, see fun (above) $DEBUG && [[ "$tty" != "not a tty" ]] && echo NOT A REAL DAEMON. NOT RUNNING WHILE LOOP. >$tty $DEBUG || { while true; do echo "Change this loop, so this silly no-op goes away." >/dev/null echo "Do something useful with your life, young padawan." >/dev/null sleep 10 done } $DEBUG && [[ "$tty" != "not a tty" ]] && sleep 3 && echo "DAEMON OUT" >$tty exit # This may never run. Why is it here then? It's pretty. # Kind of like, "The End" at the end of a movie that you # already know is over. It's always nice.
Выходные данные выглядят так, когда
DEBUG
установлено значениеtrue
. Обратите внимание, как меняются номера идентификаторов сеансов и групп процессов (SESS, PGID):источник
fork()' so the parent can exit, this returns control to the command line or shell invoking your program. ... 2.
setsid () ', чтобы стать группой процессов и лидером группы сеансов ... у нашего процесса теперь нет управляющего терминала, который является Хорошая вещь для демонов ... 3. Снова `fork () ', чтобы родительский ... мог выйти. Это означает, что мы, как лидер несессионной группы, никогда не сможем вернуть себе управляющий терминал."# double background your script to have it detach from the tty # cf. http://www.linux-mag.com/id/5981 (./program.sh &) &
источник
stdin
,stdout
,stderr
. По крайней мере, не сsh
.Это действительно зависит от того, что будет делать сам двоичный файл.
Например, я хочу создать слушателя.
Стартовый демон - это простая задача:
lis_deamon:
#!/bin/bash # We will start the listener as Deamon process # LISTENER_BIN=/tmp/deamon_test/listener test -x $LISTENER_BIN || exit 5 PIDFILE=/tmp/deamon_test/listener.pid case "$1" in start) echo -n "Starting Listener Deamon .... " startproc -f -p $PIDFILE $LISTENER_BIN echo "running" ;; *) echo "Usage: $0 start" exit 1 ;; esac
так мы запускаем демон (общий способ для всех сотрудников /etc/init.d/)
Теперь, что касается самого слушателя, это должен быть какой-то цикл / предупреждение, иначе скрипт будет делать то, что вы хотите. Например, если вы хотите, чтобы ваш сценарий спал 10 минут, а затем проснулся и спросил вас, как у вас дела, вы сделаете это с помощью
while true ; do sleep 600 ; echo "How are u ? " ; done
Вот простой слушатель, который вы можете сделать, который будет прослушивать ваши команды с удаленного компьютера и выполнять их на локальном:
слушатель:
#!/bin/bash # Starting listener on some port # we will run it as deamon and we will send commands to it. # IP=$(hostname --ip-address) PORT=1024 FILE=/tmp/backpipe count=0 while [ -a $FILE ] ; do #If file exis I assume that it used by other program FILE=$FILE.$count count=$(($count + 1)) done # Now we know that such file do not exist, # U can write down in deamon it self the remove for those files # or in different part of program mknod $FILE p while true ; do netcat -l -s $IP -p $PORT < $FILE |/bin/bash > $FILE done rm $FILE
Итак, чтобы запустить его: / tmp / deamon_test / listener start
и отправить команды из оболочки (или обернуть ее в скрипт):
test_host#netcat 10.184.200.22 1024 uptime 20:01pm up 21 days 5:10, 44 users, load average: 0.62, 0.61, 0.60 date Tue Jan 28 20:02:00 IST 2014 punt! (Cntrl+C)
Надеюсь, это поможет.
источник
$ ( cd /; umask 0; setsid your_script.sh </dev/null &>/dev/null & ) &
источник
Взгляните на инструмент демона из пакета libslack:
http://ingvar.blog.linpro.no/2009/05/18/todays-sysadmin-tip-using-libslack-daemon-to-daemonize-a-script/
В Mac OS X используйте сценарий launchd для демона оболочки.
источник
Если бы у меня был,
script.sh
и я хотел бы выполнить его из bash и оставить его работающим, даже когда я хочу закрыть сеанс bash, я бы скомбинировалnohup
и&
в конце.пример:
nohup ./script.sh < inputFile.txt > ./logFile 2>&1 &
inputFile.txt
может быть любой файл. Если в вашем файле нет входных данных, мы обычно используем/dev/null
. Итак, команда будет такой:nohup ./script.sh < /dev/null > ./logFile 2>&1 &
После этого закройте сеанс bash, откройте другой терминал и выполните:,
ps -aux | egrep "script.sh"
и вы увидите, что ваш скрипт все еще работает в фоновом режиме. Конечно, если вы хотите остановить его, выполните ту же команду (ps) иkill -9 <PID-OF-YOUR-SCRIPT>
источник
См. Проект Bash Service Manager : https://github.com/reduardo7/bash-service-manager
Пример реализации
#!/usr/bin/env bash export PID_FILE_PATH="/tmp/my-service.pid" export LOG_FILE_PATH="/tmp/my-service.log" export LOG_ERROR_FILE_PATH="/tmp/my-service.error.log" . ./services.sh run-script() { local action="$1" # Action while true; do echo "@@@ Running action '${action}'" echo foo echo bar >&2 [ "$action" = "run" ] && return 0 sleep 5 [ "$action" = "debug" ] && exit 25 done } before-start() { local action="$1" # Action echo "* Starting with $action" } after-finish() { local action="$1" # Action local serviceExitCode=$2 # Service exit code echo "* Finish with $action. Exit code: $serviceExitCode" } action="$1" serviceName="Example Service" serviceMenu "$action" "$serviceName" run-script "$workDir" before-start after-finish
Пример использования
$ ./example-service # Actions: [start|stop|restart|status|run|debug|tail(-[log|error])] $ ./example-service start # Starting Example Service service... $ ./example-service status # Serive Example Service is runnig with PID 5599 $ ./example-service stop # Stopping Example Service... $ ./example-service status # Service Example Service is not running
источник
Как и многие ответы, это не «настоящая» демонизация, а скорее альтернатива
nohup
подходу.echo "script.sh" | at now
Очевидно, есть отличия от использования
nohup
. Во-первых, нет никакого отделения от родителя. Также "script.sh" не наследует родительскую среду.Ни в коем случае это лучшая альтернатива. Это просто другой (и несколько ленивый) способ запуска процессов в фоновом режиме.
PS Я лично поддержал ответ Карло, поскольку он кажется самым элегантным и работает как из терминала, так и внутри скриптов.
источник
Вот минимальное изменение исходного предложения по созданию действующего демона в оболочке Bourne (или Bash):
#!/bin/sh if [ "$1" != "__forked__" ]; then setsid "$0" __forked__ "$@" & exit else shift fi trap 'siguser1=true' SIGUSR1 trap 'echo "Clean up and exit"; kill $sleep_pid; exit' SIGTERM exec > outfile exec 2> errfile exec 0< /dev/null while true; do (sleep 30000000 &>/dev/null) & sleep_pid=$! wait kill $sleep_pid &>/dev/null if [ -n "$siguser1" ]; then siguser1='' echo "Wait was interrupted by SIGUSR1, do things here." fi done
Пояснение:
Думаю, нет ничего проще.
источник
попробуйте выполнить с помощью &, если вы сохраните этот файл как program.sh
вы можете использовать
источник