Najlepszy sposób na stworzenie demona skryptów powłoki?

Zastanawiam się, czy jest lepszy sposób na zrobienie demona, który czeka na coś używając tylko sh niż:

#! /bin/sh
trap processUserSig SIGUSR1
processUserSig() {
  echo "doing stuff"
}

while true; do
  sleep 1000
done

W szczególności, zastanawiam się, czy jest jakiś sposób, aby pozbyć się pętli i nadal mieć coś słuchać sygnałów.

Author: Shawn J. Goff, 2010-08-07

11 answers

Użyj funkcji demona systemu, takiej jak start-stop-daemon .

W Przeciwnym Razie tak, gdzieś musi być pętla.

 40
Author: Dennis Williamson,
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-08-07 14:09:32

Tylko backgrounding skryptu (./myscript &) nie daemonizuje go. Zobacz http://www.faqs.org/faqs/unix-faq/programmer/faq / , sekcja 1.7, która opisuje, co jest konieczne, aby stać się demonem. Musisz odłączyć go od terminala, aby SIGHUP go nie zabił. Można użyć skrótu, aby skrypt wydawał się działać jak demon;

nohup ./myscript 0<&- &>/dev/null &
Wykonam zadanie. Lub, aby przechwycić zarówno stderr, jak i stdout do pliku:
nohup ./myscript 0<&- &> my.admin.log.file &

Mogą być jednak inne ważne aspekty musisz to rozważyć. Na przykład:

  • nadal będziesz miał otwarty deskryptor pliku dla skryptu, co oznacza, że katalog, w którym jest zamontowany, będzie niemontowalny. Aby być prawdziwym demonem powinieneś chdir("/") (lub cd / wewnątrz twojego skryptu) i rozwidlać się tak, aby rodzic wyszedł, a tym samym oryginalny deskryptor został zamknięty.
  • być może run umask 0. Możesz nie chcieć polegać na umask rozmówcy demona.

Na przykładzie skryptu, który zabiera wszystkie te aspekty pod uwagę, zobaczMike s' odpowiedź .

 104
Author: Ken 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
2017-05-23 12:34:15
# double background your script to have it detach from the tty
# cf. http://www.linux-mag.com/id/5981 
(./program.sh &) & 
 58
Author: carlo,
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-08-07 15:34:14

Niektóre z top-upvoted odpowiedzi tutaj brakuje niektórych ważnych części tego, co sprawia, że daemon jest demonem, w przeciwieństwie do tylko procesu w tle lub procesu w tle oddzielonego od powłoki.

To http://www.faqs.org/faqs/unix-faq/programmer/faq / opisuje, co jest konieczne, aby być demonem. I ten Uruchom skrypt Basha jako daemon implementuje setsid, choć pomija chdir do roota.

Pytanie oryginalnego plakatu było bardziej szczegółowe niż "Jak utworzyć proces demona za pomocą bash?", ale ponieważ temat i odpowiedzi omawiają ogólnie demonizowanie skryptów powłoki, myślę, że ważne jest, aby zwrócić na to uwagę (dla intruzów takich jak ja, przyglądających się drobnym szczegółom tworzenia demona).

Oto moja wersja skryptu powłoki, który zachowywałby się zgodnie z FAQ. Ustaw DEBUG na true, aby zobaczyć ładne wyjście (ale również kończy się natychmiast, zamiast zapętlać bez końca):

#!/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 man." >/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.

Wyjście wygląda tak, gdy DEBUG jest ustawione na true. Zauważ, jak zmieniają się numery ID sesji i grupy procesów (SESS, PGID):

<shell_prompt>$ bash blahd

*** PARENT, PID 5180
  PID  SESS  PGID
 5180  1708  5180
/dev/pts/6
PARENT OUT
<shell_prompt>$ 
*** CHILD, NEW SESSION, NEW PGID, PID 5188
  PID  SESS  PGID
 5188  5188  5188
not a tty
CHILD OUT

*** DAEMON, PID 5198
  PID  SESS  PGID
 5198  5188  5188
not a tty
NOT A REAL DAEMON. NOT RUNNING WHILE LOOP.
DAEMON OUT
 57
Author: Mike S,
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 12:09:56

To naprawdę zależy od tego, co zrobi sam binarny.

Na przykład Chcę stworzyć słuchacza.

Początkowy Demon to proste zadanie:

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

W ten sposób uruchamiamy demona (wspólny sposób dla wszystkich /etc / init.d / staff)

Teraz jak dla słuchacza to ja, Musi to być jakaś pętla / alert, albo spowoduje uruchomienie skryptu robić, co chcesz. Na przykład, jeśli chcesz, aby twój skrypt spał 10 min i obudź się i zapytaj jak you are doing u will do this with the

while true ; do sleep 600 ; echo "How are u ? " ; done

Oto prosty słuchacz, który u można zrobić, że będzie słuchać dla Twojego polecenia ze zdalnego komputera i wykonują je na lokalnym :

Słuchacz:

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

Aby go uruchomić:/tmp / deamon_test / listener start

I wysyłanie komend z powłoki (lub zawijanie jej do skryptu):

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)
Mam nadzieję, że to pomoże.
 4
Author: Artem,
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
2014-01-29 01:04:51

Spójrz na narzędzie daemon z pakietu libslack:

Http://ingvar.blog.linpro.no/2009/05/18/todays-sysadmin-tip-using-libslack-daemon-to-daemonize-a-script/

Na Mac OS X Użyj skryptu launchd dla demona powłoki.

 1
Author: timo,
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-08-07 14:03:50

Gdybym miał script.sh i chciałem go uruchomić z Basha i pozostawić uruchomiony nawet wtedy, gdy chcę zamknąć sesję Basha, to na końcu połączyłbym nohup i &.

Przykład: nohup ./script.sh < inputFile.txt > ./logFile 2>&1 &

inputFile.txt może to być dowolny plik. Jeśli Twój plik nie ma danych wejściowych, zwykle używamy /dev/null. Więc Komenda brzmiałaby:

nohup ./script.sh < /dev/null > ./logFile 2>&1 &

Po zamknięciu sesji bash otwórz inny terminal i wykonaj: {[7] } i zobaczysz, że Twój skrypt nadal działa w tle. Z cource, jeśli chcesz go zatrzymać to wykonaj tę samą komendę (ps) i kill -9 <PID-OF-YOUR-SCRIPT>

 1
Author: noName,
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
2015-10-01 19:43:01

Zobacz Bash Service Manager Projekt: https://github.com/reduardo7/bash-service-manager

Przykład implementacji

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

Przykład użycia

$ ./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
 0
Author: Eduardo Cuomo,
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-06-03 01:22:28

$ ( cd /; umask 0; setsid your_script.sh </dev/null &>/dev/null & ) &

 0
Author: Congbin Guo,
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
2018-03-08 22:44:17

Jak wiele odpowiedzi ta nie jest" prawdziwą " demonizacją, ale raczej alternatywą dla podejścia nohup.

echo "script.sh" | at now

Istnieją oczywiście różnice w używaniu nohup. Po pierwsze, nie ma odrywania się od rodzica. Również "script.sh" nie dziedziczy środowiska rodziców.

W żadnym wypadku nie jest to lepsza alternatywa. Jest to po prostu inny (i nieco leniwy) sposób uruchamiania procesów w tle.

P. S. ja osobiście podniosłem odpowiedź carlo jako wydaje się być najbardziej elegancki i działa zarówno z terminala, jak i wewnątrz skryptów

 0
Author: oᴉɹǝɥɔ,
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
2018-09-20 15:54:37

Spróbuj wykonać używając & jeśli zapiszesz ten plik jako program.sh

Możesz użyć

$. program.sh &
 -3
Author: jasimmk,
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-15 13:09:52