Сценарий оболочки получает правильный PID

Я написал небольшую программу, которую хочу запустить как службу на Opensuse 11.3. Это из сценария init.d, он запускает мои процессы, как я хочу, но я не получаю правильный PID.

Что мне не хватает?

echo "Starting DHCPALERT"
for (( i = 1; i <= $DHCP_AL_DAEMONS; i++ ))
do
    var="DHCP_AL_$i"
    START_CMD="exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &"
    eval $START_CMD
    echo "PID: "$!
    echo "Command: "$START_CMD
done

приводит к

PID: 47347
Command: (/sbin/startproc -p /var/log/sthserver/dhcpalert/p_2.pid -l /var/log/sthserver/dhcpalert/log_2.log /usr/sbin/dhcpalert -i eth1 -c ./test.sh -a 00:15:5D:0A:16:07 -v )&

но pidof возвращает какой-то другой pid.

Если я попытаюсь выполнить его напрямую:

exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &

Затем я получаю ошибки:

startproc:  exit status of parent of /usr/sbin/dhcpalert: 1

Я полагаю, потому что я не избегаю переменных правильно?

Это весь скрипт:

#!/bin/sh
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
DHCPALERT_BIN=/usr/sbin/dhcpalert
#-x FILE exists and is executable
test -x $DHCPALERT_BIN || { echo "$DHCPALERT_BIN not installed"; 
    if [ "$1" = "stop" ]; then exit 0;
    else exit 5; fi; }

# Check for existence of needed config file and read it
DHCPALERT_CONFIG=/etc/sysconfig/dhcpalert
#-r FILE exists and is readable
test -r $DHCPALERT_CONFIG || { echo "$DHCPALERT_CONFIG not existing";
    if [ "$1" = "stop" ]; then exit 0;
    else exit 6; fi; }

# Read config to system VARs for this shell session only same as "source FILE"
. $DHCPALERT_CONFIG

#check for exitstence of the log dir
if [ -d "$DHCP_AL_LOG_DIR" ]; then
        echo "exists 1"
        echo "exists 2"
        echo "exists 3"
        if [ "$1" = "start" ]; then
            echo "Deleting all old log files from: "
            echo "Dir:... "$DHCP_AL_LOG_DIR
            rm -R $DHCP_AL_LOG_DIR
            mkdir $DHCP_AL_LOG_DIR
        fi
    else
        echo "does not exist 1"
        echo "does not exist 2"
        echo "does not exist 3"
        echo "Directory for Logfiles does not exist."
        echo "Dir:... "$DHCP_AL_LOG_DIR
        echo "Createing dir..."
        mkdir $DHCP_AL_LOG_DIR
    fi


. /etc/rc.status

# Reset status of this service
rc_reset

case "$1" in
    start)
    echo "Starting DHCPALERT"
    for (( i = 1; i <= $DHCP_AL_DAEMONS; i++ ))
    do
        var="DHCP_AL_$i"

        exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &

       # START_CMD="exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &"
       # eval $START_CMD
        echo "PID: "$!
       # echo "Command: "$START_CMD
    done

    rc_status -v
    ;;
    stop)
    echo -n "Shutting down DHCPALERT "

    /sbin/killproc -TERM $DHCPALERT_BIN
    rc_status -v
    ;;
    try-restart|condrestart)
    if test "$1" = "condrestart"; then
        echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
    fi
    $0 status
    if test $? = 0; then
        $0 restart
    else
        rc_reset    # Not running is not a failure.
    fi
    rc_status
    ;;
    restart)
    $0 stop
    $0 start
    rc_status
    ;;
    force-reload)
    echo -n "Reload service DHCPALERT "
    /sbin/killproc -HUP $DHCPALERT_BIN
    rc_status -v
    ;;
    reload)
    echo -n "Reload service DHCPALERT "
    /sbin/killproc -HUP $DHCPALERT_BIN
    rc_status -v
    ;;
    status)
    echo -n "Checking for service DHCPALERT "
    /sbin/checkproc $DHCPALERT_BIN
    rc_status -v
    ;;
    probe)

    test /etc/DHCPALERT/DHCPALERT.conf -nt /var/run/DHCPALERT.pid && echo reload
    ;;
    *)
    echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
    exit 1
    ;;
esac
rc_exit

Конфигурационный файл:

## Specifiy where to store the Pid files
DHCP_AL_PID_DIR="/var/log/sthserver/dhcpalert/"
##
## Specifiy where to store the Log file
DHCP_AL_LOG_DIR="/var/log/sthserver/dhcpalert/"
##
## is needed to determine how many vars should be read and started!
DHCP_AL_DAEMONS="2"
##                        
## Then DHCP_AL_<number> to specify the command that one instance of 
## dhcpalert should be started
DHCP_AL_1="-i eth0 -c ./test.sh -a 00:15:5D:0A:16:06 -v"
DHCP_AL_2="-i eth1 -c ./test.sh -a 00:15:5D:0A:16:07 -v"

person simonides    schedule 12.08.2014    source источник
comment
Какой линукс вы используете? А какая оболочка?   -  person John Zwinck    schedule 12.08.2014
comment
извините думал я это уже писал. Это openuse 11.3 и bash   -  person simonides    schedule 12.08.2014
comment
Почему вы используете eval для запуска команды?   -  person hek2mgl    schedule 12.08.2014
comment
Потому что у меня были проблемы с правильным экранированием переменных, и после поиска в Google это сработало. Как бы я сделал это без?   -  person simonides    schedule 12.08.2014
comment
Можно попробовать без eval? /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &   -  person konsolebox    schedule 12.08.2014
comment
без eval это то, что возвращается pepi-vm:/etc/init.d # startproc: exit status of parent of /usr/sbin/dhcpalert: 1 startproc: exit status of parent of /usr/sbin/dhcpalert: 1   -  person simonides    schedule 12.08.2014
comment
@fridolin69 Можете ли вы показать все части вашего сценария?   -  person konsolebox    schedule 12.08.2014
comment
@konsolebox Я добавил скрипт и файл конфигурации. Для начала я использовал каркасный скрипт от Opensuse.   -  person simonides    schedule 12.08.2014
comment
Возможно ли, чтобы скрипт работал как #!/bin/bash вместо этого?   -  person konsolebox    schedule 12.08.2014
comment
Сделал, но без изменений.   -  person simonides    schedule 12.08.2014


Ответы (2)


Добавьте к нему exec, чтобы предотвратить разветвление:

START_CMD="(exec /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}") &"

Обновлять. Пожалуйста, попробуйте этот скрипт:

#!/bin/bash
# Check for missing binaries (stale symlinks should not happen)
# Note: Special treatment of stop for LSB conformance
DHCPALERT_BIN=/usr/sbin/dhcpalert
#-x FILE exists and is executable
[[ -x $DHCPALERT_BIN ]] || {
    echo "$DHCPALERT_BIN not installed"
    if [ "$1" = "stop" ]; then
        exit 0
    else
        exit 5
    fi
}

# Check for existence of needed config file and read it
DHCPALERT_CONFIG=/etc/sysconfig/dhcpalert
#-r FILE exists and is readable
[[ -r $DHCPALERT_CONFIG ]] || {
    echo "$DHCPALERT_CONFIG not existing"
    if [[ $1 == stop ]]; then
        exit 0
    else
        exit 6
    fi
}

# Read config to system VARs for this shell session only same as "source FILE"
. "$DHCPALERT_CONFIG"

#check for exitstence of the log dir

CREATE_DIR=false

if [[ -d $DHCP_AL_LOG_DIR ]]; then
    echo "exists 1"
    echo "exists 2"
    echo "exists 3"
    if [[ $1 == start ]]; then
        echo "Deleting all old log files from: "
        echo "Dir:... $DHCP_AL_LOG_DIR"
        rm -R "$DHCP_AL_LOG_DIR"
        CREATE_DIR=true
    fi
else
    echo "does not exist 1"
    echo "does not exist 2"
    echo "does not exist 3"
    echo "Directory for Logfiles does not exist."
    CREATE_DIR=true
fi

if [[ $CREATE_DIR == true ]]; then
    echo "Dir:... $DHCP_AL_LOG_DIR"
    echo "Createing dir..."
    mkdir "$DHCP_AL_LOG_DIR" || {
        echo "Failed to create directory $DHCP_AL_LOG_DIR"
        exit 1
    }
fi

. /etc/rc.status

# Reset status of this service
rc_reset

case "$1" in
start)
    echo "Starting DHCPALERT"
    for (( I = 1; I <= DHCP_AL_DAEMONS; ++I )); do
        REF="DHCP_AL_${I}[@]"
        COMMAND=(/sbin/startproc -p "${DHCP_AL_PID_DIR}p_${I}.pid" -l "${DHCP_AL_LOG_DIR}log_${I}.log" "$DHCPALERT_BIN" "${!REF}")
        echo "COMMAND: ${COMMAND[*]}"
        "${COMMAND[@]}" &
        PID=$!
        echo "PID: $PID"
    done
    rc_status -v
    ;;
stop)
    echo -n "Shutting down DHCPALERT "
    /sbin/killproc -TERM "$DHCPALERT_BIN"
    rc_status -v
    ;;
try-restart|condrestart)
    [[ $1 == condrestart ]] && echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}"
    "$0" status  ## ??
    if [[ $? -eq 0 ]]; then
        "$0" restart
    else
        rc_reset    # Not running is not a failure.
    fi
    rc_status
    ;;
restart)
    "$0" stop
    "$0" start
    rc_status
    ;;
    force-reload)
    echo -n "Reload service DHCPALERT "
    /sbin/killproc -HUP "$DHCPALERT_BIN"
    rc_status -v
    ;;
reload)
    echo -n "Reload service DHCPALERT "
    /sbin/killproc -HUP "$DHCPALERT_BIN"
    rc_status -v
    ;;
status)
    echo -n "Checking for service DHCPALERT "
    /sbin/checkproc "$DHCPALERT_BIN"
    rc_status -v
    ;;
probe)
    [[ /etc/DHCPALERT/DHCPALERT.conf -nt /var/run/DHCPALERT.pid ]] & echo reload
    ;;
*)
    echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
    exit 1
    ;;
esac

rc_exit

Файл конфигурации:

## Specifiy where to store the Pid files
DHCP_AL_PID_DIR="/var/log/sthserver/dhcpalert/"
##
## Specifiy where to store the Log file
DHCP_AL_LOG_DIR="/var/log/sthserver/dhcpalert/"
##
## is needed to determine how many vars should be read and started!
DHCP_AL_DAEMONS="2"
##
## Then DHCP_AL_<number> to specify the command that one instance of
## dhcpalert should be started
DHCP_AL_1=(-i eth0 -c ./test.sh -a 00:15:5D:0A:16:06 -v)
DHCP_AL_2=(-i eth1 -c ./test.sh -a 00:15:5D:0A:16:07 -v)
person konsolebox    schedule 12.08.2014
comment
все еще неправильные, даже если я удалю скобки - person simonides; 12.08.2014
comment
попробовал, спасибо, но файл pid не создается startproc, это то, что я должен сделать сам, по крайней мере, это то, что я понял из чтения справочной страницы и stackoverflow. Таким образом, команда чтения явно не работает. - person simonides; 12.08.2014
comment
@fridolin69 Значит, -p "${DHCP_AL_PID_DIR}p_${I}.pid" не очень помогает? - person konsolebox; 12.08.2014
comment
Кроме того, вы создаете два экземпляра вашего dhcpalert приложения. Как вы планируете управлять обоими PID? - person konsolebox; 12.08.2014
comment
Я думаю, что это работает так, как должно. Но не создает файл, этот файл только для чтения, и если уже есть процесс с pid и именем (dhcpalert), то нет! запускается новый процесс. Но я не понимаю, как мне создать этот файл, так как у меня проблемы с поиском правильного pid. Это становится удобным, если кто-то пытается запустить его дважды, но я предполагаю, что с этим можно справиться с помощью if [уже запущенного], then... - person simonides; 12.08.2014
comment
Но у меня есть другая проблема с файлами журнала. Они создаются, но остаются пустыми, хотя я что-то распечатываю в первой строке программы dhcpalert, есть идеи по этому поводу? - person simonides; 12.08.2014
comment
Я планировал управлять экземплярами с разными файлами pid. Я должен признать, что мне трудно понять, что именно вы здесь написали. REF="DHCP_AL_${I}[@]" зачем мне [@] здесь? @ не является ссылкой на все параметры, переданные сценарию? - person simonides; 13.08.2014
comment
@ fridolin69 Чтобы предотвратить использование eval, я решил сохранить ваши аргументы в виде массивов. Посмотрите, как они теперь хранятся в вашем файле конфигурации. Ссылка — это форма косвенного раскрытия переменной, как будто она заставляет вас делать "${DHCP_AL_1[@]}". - person konsolebox; 13.08.2014
comment
В любом случае, я до сих пор мало читаю, как все устроено, но возвращаясь к нашей основной проблеме, не могли бы вы попробовать прочитать $! еще раз? "${COMMAND[@]}" уже хорошо работает, верно? Я сделал обновление для него. - person konsolebox; 13.08.2014
comment
Он печатает неправильные pid, он печатает 6550, а реальный процесс имеет 6552, но числа всегда были близки. - person simonides; 13.08.2014
comment
@ fridolin69 Я думаю, что вы действительно хотите использовать start_daemon, а не startproc. Согласно документации: start_daemon не поддерживает параметры -(t|T) ‹sec› и -(w|W ‹список файлов›) для ожидания успеха и параметр -s для нового сеанса, поскольку этот вариант не разветвляется для запуска исполняемого файла. - person konsolebox; 13.08.2014
comment
start_daemon — это символическая ссылка на startproc в этой системе. - person simonides; 13.08.2014
comment
@fridolin69 Просто попробуй. Возможно, двоичный файл ведет себя иначе, если вызывается как start_daemon. - person konsolebox; 13.08.2014
comment
ууууууууууууууууууууууууууууууу а как же так? Я не понимаю. Я выполнил это дважды, и PID были правильными :). У вас есть идеи, почему лог-файлы остаются пустыми? И зачем мне скобки в конфиге? - person simonides; 13.08.2014
comment
Это похоже на работу bash в режиме POSIX при вызове как sh. Вы заметили, что /bin/sh связано с /bin/bash. Разница между start_daemon и startproc заключается в том, что start_daemon не выполняет разветвления, поэтому имеющийся у него pid становится pid процесса, который он вызывает. В файле конфигурации вы храните аргументы в виде массивов, чтобы они были правильно сформированы даже с пробелами. См. gnu.org/software/bash/manual/html_node/Arrays.html. . - person konsolebox; 13.08.2014
comment
Я не уверен, почему они пусты. Они показывают сообщения с startproc? - person konsolebox; 13.08.2014
comment
Ну, я думал, что не могу или не должен создавать массивы в файле конфигурации. Но в любом случае, если это работает, почему бы и нет... как мне прочитать [*] and [@]? ничего этого не могу найти. Я имею в виду, что я обнаружил, что символ @ является ссылкой на все переданные параметры, но почему это должно быть добавлено, когда команда объединяется строкой раньше? Файлы журналов пусты с обеими командами, за исключением случаев, когда я передаю неправильный интерфейс и печатаются ошибки. Но зато есть и короткое сообщение о запуске программы, которое всегда печатается. - person simonides; 13.08.2014
comment
@fridolin69 Предлагаю прочитать учебник по массивам: thegeekstuff.com/2010/06 /bash-массив-учебник. И ваша лучшая ссылка, когда дело доходит до сценария bash, — это man bash и help. Онлайн-версия также легко читается: gnu.org/software/bash/manual . "${x[@]}" расширяется до нескольких аргументов, а "${x[*]}" расширяется только как одна строка, где каждый элемент разделяется первым значением в IFS. - person konsolebox; 13.08.2014
comment
Если какие-то сообщения отображаются в файлах журналов, то, по крайней мере, мы можем сказать, что start_daemon хорошо перенаправляет вывод на него. - person konsolebox; 13.08.2014

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

Есть два решения: первое — не запускать команду /sbin/startproc в подоболочке, а напрямую и помещать ее в фоновый режим. Второе решение — отслеживать файл pid, созданный /sbin/startproc.

person Some programmer dude    schedule 12.08.2014