Me pregunto si hay una mejor manera de hacer un demonio que espera algo usando solo sh que:
#! /bin/sh
trap processUserSig SIGUSR1
processUserSig() {
echo "doing stuff"
}
while true; do
sleep 1000
done
En particular, me pregunto si hay alguna forma de deshacerse del bucle y aún hacer que la cosa escuche las señales.
Respuestas:
Utilice la función de demonio de su sistema, como start-stop-daemon .
De lo contrario, sí, tiene que haber un bucle en alguna parte.
fuente
Simplemente
./myscript &
poner en segundo plano su script ( ) no lo demonizará. Consulte http://www.faqs.org/faqs/unix-faq/programmer/faq/ , sección 1.7, que describe lo que se necesita para convertirse en un demonio. Debes desconectarlo del terminal para queSIGHUP
no lo mate. Puede utilizar un atajo para hacer que un script parezca actuar como un demonio;hará el trabajo. O, para capturar stderr y stdout en un archivo:
Sin embargo, puede haber otros aspectos importantes que debe tener en cuenta. Por ejemplo:
chdir("/")
(ocd /
dentro de su script), y bifurcar para que el padre salga y, por lo tanto, el descriptor original se cierre.umask 0
. Es posible que no desee depender de la umask del llamador del demonio.Para un ejemplo de un script que toma todos estos aspectos en cuenta, ver la respuesta de Mike S' .
fuente
0<&-
hacer? No es obvio lo que logra esa secuencia de personajes.0<&-
se pretende hacer. Encontré este enlace que lo explica.0<&-
cierra stdin (fd 0). De esa manera, si su proceso lee accidentalmente desde stdin (fácil de hacer), obtendrá un error en lugar de quedarse para siempre esperando a que aparezcan los datos.A algunas de las respuestas votadas aquí les faltan algunas partes importantes de lo que hace que un demonio sea un demonio, en lugar de un proceso en segundo plano o un proceso en segundo plano separado de un shell.
Este http://www.faqs.org/faqs/unix-faq/programmer/faq/ describe lo que se necesita para ser un demonio. Y este script Ejecutar bash como demonio implementa el setid, aunque pierde el chdir a la raíz.
La pregunta del póster original era en realidad más específica que "¿Cómo creo un proceso de demonio usando bash?", Pero dado que el tema y las respuestas discuten la demonización de los scripts de shell en general, creo que es importante señalarlo (para intrusos como yo que investigan el finos detalles de la creación de un demonio).
Aquí está mi interpretación de un script de shell que se comportaría de acuerdo con las preguntas frecuentes. Configure DEBUG en
true
para ver una salida bonita (pero también sale inmediatamente en lugar de recorrer un bucle sin fin):#!/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.
La salida se ve así cuando
DEBUG
se establece entrue
. Observe cómo cambian los números de ID de grupo de proceso y sesión (SESS, PGID):fuente
fork()' so the parent can exit, this returns control to the command line or shell invoking your program. ... 2.
setsid () 'para convertirse en un grupo de proceso y líder de grupo de sesión ... nuestro proceso ahora no tiene una terminal de control, que es algo bueno para los demonios ... 3. `fork () 'de nuevo para que el padre ... pueda salir. Esto significa que nosotros, como líderes de grupo que no son de sesión, nunca podremos recuperar una terminal controladora".# double background your script to have it detach from the tty # cf. http://www.linux-mag.com/id/5981 (./program.sh &) &
fuente
stdin
,stdout
,stderr
. Al menos no consh
.Realmente depende de lo que haga el binario en sí.
Por ejemplo, quiero crear un oyente.
El demonio inicial es una tarea sencilla:
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
así es como iniciamos el demonio (forma común para todo el personal de /etc/init.d/)
ahora en cuanto al oyente en sí, debe ser algún tipo de bucle / alerta o de lo contrario activará el script para hacer lo que quieras. Por ejemplo, si desea que su guión duerma 10 minutos y se despierte y le pregunte cómo está, lo hará con el
while true ; do sleep 600 ; echo "How are u ? " ; done
Aquí está el oyente simple que puede hacer que escuchará sus comandos desde una máquina remota y los ejecutará en local:
oyente:
#!/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
Entonces para comenzar: / tmp / deamon_test / listener start
y para enviar comandos desde el shell (o ajustarlo al script):
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)
Espero que esto ayude.
fuente
$ ( cd /; umask 0; setsid your_script.sh </dev/null &>/dev/null & ) &
fuente
Eche un vistazo a la herramienta daemon del paquete libslack:
http://ingvar.blog.linpro.no/2009/05/18/todays-sysadmin-tip-using-libslack-daemon-to-daemonize-a-script/
En Mac OS X, utilice un script Launchd para el demonio de shell.
fuente
Si tuviera un
script.sh
y quisiera ejecutarlo desde bash y dejarlo ejecutándose incluso cuando quiera cerrar mi sesión de bash, entonces combinaríanohup
y&
al final.ejemplo:
nohup ./script.sh < inputFile.txt > ./logFile 2>&1 &
inputFile.txt
puede ser cualquier archivo. Si su archivo no tiene entrada, usualmente usamos/dev/null
. Entonces el comando sería:nohup ./script.sh < /dev/null > ./logFile 2>&1 &
Después de eso, cierre su sesión de bash, abra otra terminal y ejecute:
ps -aux | egrep "script.sh"
y verá que su script todavía se está ejecutando en segundo plano. Por supuesto, si desea detenerlo, ejecute el mismo comando (ps) ykill -9 <PID-OF-YOUR-SCRIPT>
fuente
Consulte el proyecto Bash Service Manager : https://github.com/reduardo7/bash-service-manager
Ejemplo de implementación
#!/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
Ejemplo de uso
$ ./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
fuente
Como muchas respuestas, esta no es una demonización "real" sino más bien una alternativa al
nohup
enfoque.echo "script.sh" | at now
Obviamente, existen diferencias con el uso
nohup
. Para empezar, no hay separación de los padres en primer lugar. Además, "script.sh" no hereda el entorno de los padres.De ninguna manera esta es una mejor alternativa. Es simplemente una forma diferente (y algo perezosa) de iniciar procesos en segundo plano.
PD: personalmente voté a favor de la respuesta de carlo, ya que parece ser la más elegante y funciona tanto desde la terminal como desde los scripts internos
fuente
Aquí está el cambio mínimo a la propuesta original para crear un demonio válido en Bourne shell (o 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
Explicación:
Supongo que no hay nada más simple que eso.
fuente
intente ejecutar usando & si guarda este archivo como program.sh
puedes usar
fuente