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

管道中的bash脚本如何检测到它';的数据源已死亡。?,bash,Bash,我在一台没有logrorate的旧机器上工作 [实际上,它有busybox 0.6,这在大多数情况下是“形式无效的”。] 我有openvpn运行,我希望能够看到它一直在做什么。我正在使用的openvpn可以将进度信息输出到标准输出或命名日志文件 我试图找到一种方法来停止使用一个日志文件,并在另一个日志文件上启动它,但失败了。也许某个SIGUSR或其他东西会使它关闭并重新打开输出文件,但我找不到它 所以我编写了一个脚本,它读取stdin,并将输出定向到一个旋转日志文件 所以现在我需要做的就是将op

我在一台没有logrorate的旧机器上工作

[实际上,它有busybox 0.6,这在大多数情况下是“形式无效的”。]

我有openvpn运行,我希望能够看到它一直在做什么。我正在使用的openvpn可以将进度信息输出到标准输出或命名日志文件

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

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

所以现在我需要做的就是将openvpn的输出通过管道传输到它

工作完成了

除了如果我杀死openvpn,处理其输出的脚本将永远运行。它已经无能为力了,所以我希望它自动死亡

有没有办法在脚本“EOF on STDIN”或使用“find the process ID which being my STDIN”之类的东西中捕获这种情况


我明白这与问题相似 但这并不完全是因为我无法控制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
更改此项:

        read line
        echo ${line} >> ${logFile}
为此:

        read line || exit
        printf %s "$line" >> "$logFile"
因此,如果读取失败(因为您已达到EOF),您将退出

更好的是,将其更改为:

        IFS= read -r line || exit
这样就不会丢弃前导空格,也不会将反斜杠视为特殊字符

当你这样做的时候,一定要改变这一点:

        read line
        echo ${line} >> ${logFile}
为此:

        read line || exit
        printf %s "$line" >> "$logFile"

这样,如果
$line
有一个前导
-
,或者包含
*
或诸如此类的内容,您就不会遇到问题。

您能发布脚本吗?