Подтвердить что ты не робот

Лучший способ сделать оболочку script демоном?

Мне интересно, есть ли лучший способ сделать демона, который ждет чего-то, используя только sh, чем:

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

while true; do
  sleep 1000
done

В частности, мне интересно, есть ли способ избавиться от цикла и до сих пор слушать музыку.

4b9b3361

Ответ 1

Используйте средство системного демона, например start-stop-daemon.

В противном случае, да, где-то должен быть цикл.

Ответ 2

Простое описание script (./myscript &) не приведет к его демонизации. См. http://www.faqs.org/faqs/unix-faq/programmer/faq/, раздел 1.7, в котором описывается, что необходимо для того, чтобы стать демоном. Вы должны отключить его от терминала, чтобы SIGHUP не убивал его. Вы можете сделать ярлык, чтобы заставить script отображаться как демон,

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

выполнит эту работу. Или, чтобы захватить stderr и stdout в файл:

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

Однако могут быть и другие важные аспекты, которые необходимо учитывать. Например:

  • У вас все еще будет дескриптор файла, открытый для script, что означает, что каталог, в котором он был установлен, был бы непомонтирован. Чтобы быть истинным демоном, вы должны chdir("/") (или cd / внутри вашего script), и fork, чтобы родительский элемент вышел, и, следовательно, исходный дескриптор закрыт.
  • Возможно, запустите umask 0. Возможно, вы не захотите зависеть от umask вызывающего лица демона.

Для примера script, который учитывает все эти аспекты, см. ответ Майка С..

Ответ 3

# double background your script to have it detach from the tty
# cf. http://www.linux-mag.com/id/5981 
(./program.sh &) & 

Ответ 4

В некоторых из вышеперечисленных ответов отсутствуют некоторые важные части того, что делает демона демоном, а не только фоновым процессом, или фоновым процессом, отделенным от оболочки.

Этот http://www.faqs.org/faqs/unix-faq/programmer/faq/ описывает, что нужно, чтобы быть демоном. И этот Run bash script как демон реализует setid, хотя он пропускает chdir для root.

Исходный вопрос с плакатом был более конкретным, чем "Как создать процесс демона с помощью bash?", но так как тема и ответы обсуждают демонрование сценариев оболочки вообще, я думаю, что важно указать это (для нарушителей как я смотрю на мелкие детали создания демона).

Здесь мое исполнение оболочки script, которая будет вести себя в соответствии с 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" "[email protected]" </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" "[email protected]" &
    $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 pretty.
     # Kind of like, "The End" at the end of a movie that you
     # already know is over. It always nice.

Результат выглядит так, когда DEBUG установлен на true. Обратите внимание, как изменяются номера идентификаторов сеанса и группы процессов (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

Ответ 5

Это действительно зависит от того, что будет делать сам двоичный файл.

Например, я хочу создать несколько слушателей.

Начальный Daemon - простая задача:

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/)

теперь, как для слушателя, сам, Это должен быть какой-то цикл/оповещение или иначе, что вызовет script делать то, что хотите. Например, если вы хотите, чтобы ваш script спал 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

Итак, чтобы запустить UP:/tmp/deamon_test/startener start

и отправить команды из оболочки (или обернуть ее на 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)

Надеюсь, это поможет.

Ответ 7

Если у меня был 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", и вы увидите, что ваш script все еще работает в фоновом режиме. Конечно, если вы хотите остановить его, выполните ту же команду (ps) и kill -9 <PID-OF-YOUR-SCRIPT>

Ответ 8

Смотрите проект 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

Ответ 9

попробуйте выполнить с помощью & если вы сохраните этот файл как program.sh

вы можете использовать

$. program.sh &