[bash] 쉘 스크립트 데몬을 만드는 가장 좋은 방법은 무엇입니까?

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되지 않도록 터미널에서 연결을 해제해야 합니다. 바로 가기를 사용하여 스크립트가 데몬처럼 작동하도록 만들 수 있습니다.

nohup ./myscript 0<&- &>/dev/null &

일을 할 것입니다. 또는 stderr 및 stdout을 모두 파일에 캡처하려면 다음을 수행하십시오.

nohup ./myscript 0<&- &> my.admin.log.file &

그러나 고려해야 할 더 중요한 측면이있을 수 있습니다. 예를 들면 :

  • 스크립트에 대한 파일 설명자가 여전히 열려 있습니다. 즉, 마운트 된 디렉토리가 마운트 해제 될 수 있습니다. 진정한 데몬이 되려면 chdir("/")(또는 cd /스크립트 내부에서) 부모가 종료되도록 포크하여 원래 설명자가 닫힙니다.
  • 아마도 umask 0. 데몬 호출자의 umask에 의존하고 싶지 않을 수 있습니다.

이러한 모든 측면을 고려한 스크립트의 예는 Mike S의 답변을 참조하십시오 .


답변

여기에서 가장 많이 뽑힌 답변 중 일부는 백그라운드 프로세스 또는 셸에서 분리 된 백그라운드 프로세스와 달리 데몬을 데몬으로 만드는 중요한 부분이 누락되었습니다.

http://www.faqs.org/faqs/unix-faq/programmer/faq/는 데몬으로 필요한 것을 설명합니다. 그리고이 Run bash script as daemon 은 setsid를 구현하지만 루트에 대한 chdir이 누락되었습니다.

원래 포스터의 질문은 실제로 “Bash를 사용하여 데몬 프로세스를 만드는 방법”보다 더 구체적 이었지만 주제와 답변은 일반적으로 쉘 스크립트 데몬 화에 대해 논의하기 때문에 지적하는 것이 중요하다고 생각합니다. 데몬 생성에 대한 세부 정보).

다음은 FAQ에 따라 작동하는 쉘 스크립트의 제 표현입니다. true예쁜 출력을 보려면 DEBUG를 로 설정 하십시오 (그러나 끝없이 반복되는 대신 즉시 종료됩니다).

#!/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. 세션 및 프로세스 그룹 ID (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


답변

# double background your script to have it detach from the tty
# cf. http://www.linux-mag.com/id/5981 
(./program.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/ staff에 대한 일반적인 방법).

이제 리스너 자체는 일종의 루프 / 경고이거나 스크립트가 원하는 작업을 수행하도록 트리거해야합니다. 예를 들어 스크립트가 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 스크립트를 사용합니다.