【问题标题】:Shell script get the right PIDShell 脚本获取正确的 PID
【发布时间】:2014-10-05 12:47:31
【问题描述】:

我写了一个小程序,我想在 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"

【问题讨论】:

  • 您使用的是哪种 Linux?什么外壳?
  • 抱歉,我已经写过了。它是 opensuse 11.3 和 bash
  • 为什么要使用eval来启动命令?
  • 因为我在正确转义变量时遇到了问题,并且在谷歌搜索之后它起作用了。没有我怎么办?
  • 没有eval可以试试吗? /sbin/startproc -p "$DHCP_AL_PID_DIR"p_"$i".pid -l "$DHCP_AL_LOG_DIR"log_"$i".log "$DHCPALERT_BIN" "${!var}" &amp;

标签: linux shell pid init.d


【解决方案1】:

添加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)

【讨论】:

  • 即使我删除括号仍然是错误的
  • 试过了,谢谢,但是 pid 文件不是由 startproc 创建的,这将是我必须自己做的事情,至少这是我从阅读手册页和 stackoverflow 中了解到的。所以读取命令显然失败了。
  • @fridolin69 我认为你真正想要使用的是start_daemon 而不是startproc。根据文档: start_daemon 不支持选项 -(t|T) 也不支持 -(w|W ) 等待成功和选项 -s 用于新会话,因为此变体不分叉启动可执行文件。
  • @fridolin69 试试吧。如果调用为start_daemon,二进制文件的行为可能会有所不同。
  • wooooooow 但这怎么可能呢?我不明白。我执行了两次,PID 是正确的:)。你知道为什么日志文件是空的吗?为什么我需要配置文件中的括号?
【解决方案2】:

当您在括号内有一个 shell-command 时,您将启动一个新的子 shell。你在后台运行这个子shell,它就是你通过$!获得的子shell进程ID。

有两种解决方案:第一种是不在子shell中运行/sbin/startproc命令,而是直接在后台运行。第二种方案是监控/sbin/startproc创建的pid文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-02
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多