如何管道中的bash脚本检测到它的数据源已经死亡。

时间:2014-11-28 15:49:12

标签: bash

我正在研究一台没有经过验证的可怕旧机器。

[实际上它有busybox 0.6,这对于大多数用途来说都是'无形'。 ]

我有openvpn运行,我希望能够看到它的功能。我正在使用的openvpn可以将进度信息输出到stdout或命名日志文件。

我尝试过但未能找到一种方法来停止使用一个日志文件并在另一个日志文件上启动它。也许一些SIGUSR或其他东西会使它关闭并重新打开输出文件,但我找不到它。

所以我编写了一个从stdin读取的脚本,并将输出定向到一个旋转的日志文件。

所以现在我需要做的就是将openvpn的输出传递给它。

完成工作。

除非我杀死openvpn,处理其输出的脚本才会永远运行。它没有什么可以做的,所以我希望它能自动消亡。

有没有办法在脚本“EOF on STDIN”或某些东西中使用“查找正在为我的标准输入的进程ID”或其他什么来捕获这种情况?


我发现这类似于问题    "Tee does not exit after pipeline it's on has finished" 但这并不是因为我无法控制openvpn的行为(除了我可以杀死它)。我确实可以控制接收openvpn输出的脚本,但无法解决如何检测openvpn或管道死亡的问题。

我的上级脚本大致是:

vpn_command="openvpn --writepid ${sole_vpn_pid_file}             \
                     --config   /etc/openvpn/openvpn.conf        \
                     --remote   ${VPN_HOST} ${VPN_PORT} "

# collapse sequences of multiple spaces to one space
vpn_command_tight=$(echo -e ${vpn_command})  # must not quote the parameter

# We pass the pid file over explicitly in case we ever want to use multiple VPNs.
( ./${launchAndWaitScriptFullName} "${vpn_command_tight}" "${sole_vpn_pid_file}" 2>&1 | \
  ./vpn-log-rotate.sh 10000 /var/log/openvpn/openvpn.log ) &

如果我杀了openvpn进程,那么“vpn-log-rotate.sh”就会继续运行。

即:

#!/bin/sh

# @file vpn-log-rotate.sh
#
# @brief  rotates stdin out to 2 levels of log files
#
# @param    linesPerFile    Number of lines to be placed in each log file.
# @param    logFile         Name of the primary log file.
#
# Archives the last log files on entry to .last files, then starts clean.
#
# @FIXME DGC 28-Nov-2014
#      Note that this script does not die if the previous stage of the pipeline dies.
#      It is possible that use of "trap SIGPIPE" or similar might fix that.
#
# @copyright Copyright Dexdyne Ltd 2014. All rights reserved.
#
# @author DGC

linesPerFile="$1"
logFile="$2"

# The location of this script as an absolute path. ( e.g. /home/Scripts )
scriptHomePathAndDirName="$(dirname "$(readlink -f $0)")"

# The name of this script
scriptName="$( basename $0 )"

. ${scriptHomePathAndDirName}/vpn-common.inc.sh
# Includes /sbin/script_start.inc.sh
# Reads config file
# Sets up vpn_temp_directory
# Sets up functions to obtain process id, and check if process is running.
# includes vpn-script-macros

# Remember our PID, to make it easier for a supervisor script to locate and kill us.
echo $$ > ${vpn_log_rotate_pid_file}

onExit()
{
    echo "vpn-log-rotate.sh is exiting now"
    rm -f ${vpn_log_rotate_pid_file}
}
trap "( onExit )" EXIT

logFileRotate1="${logFile}.1"

# Currently remember the 2 previous logs, in a rather knife-and-fork manner.
logFileMinus1="${logfile}.minus1"
logFileMinus2="${logfile}.minus2"

logFileRotate1Minus1="${logFileRotate1}.minus1"
logFileRotate1Minus2="${logFileRotate1}.minus2"

# The primary log file exist, rename it to be the rotated version.
rotateLogs()
{
    if [ -f "${logFile}" ]
    then
        mv -f "${logFile}" "${logFileRotate1}"
    fi
}

# The log files exist, rename them to be the archived copies.
archiveLogs()
{
    if [ -f "${logFileMinus1}" ]
    then
        mv -f "${logFileMinus1}"  "${logFileMinus2}"
    fi
    if [ -f "${logFile}" ]
    then
        mv -f "${logFile}"        "${logFileMinus1}"
    fi
    if [ -f "${logFileRotate1Minus1}" ]
    then
        mv -f "${logFileRotate1Minus1}" "${logFileRotate1Minus2}"
    fi
    if [ -f "${logFileRotate1}" ]
    then
        mv -f "${logFileRotate1}" "${logFileRotate1Minus1}"
    fi
    }

archiveLogs
rm -f "${LogFile}"
rm -f "${logFileRotate1}"

while true
do
    lines=0
    while [ ${lines} -lt ${linesPerFile} ]
    do
        read line

        lines=$(( ${lines} + 1 ))

        #echo $lines

        echo ${line} >> ${logFile}
    done

    mv -f "${logFile}" "${logFileRotate1}"

done

exit_0

1 个答案:

答案 0 :(得分:1)

改变这个:

        read line

到此:

        read line || exit

因此,如果read - 失败(因为您已达到EOF),则退出。

更好的是,将其更改为:

        IFS= read -r line || exit

这样您就不会丢弃前导空格,也不会将反斜杠视为特殊字符。

当你在这里时,一定要改变它:

        echo ${line} >> ${logFile}

到此:

        printf %s "$line" >> "$logFile"

如果$line有一个前导-,或包含*?,或其他什么,则不会遇到问题。