出力リダイレクトによるバッファリング防止

出力リダイレクトによるバッファリング防止

デフォルトでは、すべての出力をstdoutコントラストエラーとしてマークし、日付/タイムスタンプを追加し、出力が出た関数の名前も含めるためにスクリプトで使用できるいくつかの関数を作成しようとしています。バッファリングの問題を除いて、これはすべて行われました。私の出力は基本的に年代順ではありません。

unbuffer、sync、stdbufなどの組み合わせを試しましたが、正しく機能しません。なぜこれが失敗するのかについての助けや説明をしてくれてありがとう。また、これをより簡単に行うためのヒントをお勧めします。これまでの関数名を取得するには、すべての関数呼び出しでリダイレクトを再構成する必要がありました。

#!/bin/bash

function stdOutput
{
    typeset strLogFile=$1; shift
    typeset strLogID=$1; shift
    while IFS='' read -r strInput
    do
        echo "$(eval echo ${strLogID})${strInput}" && echo "$(eval echo ${strLogID})${strInput}" >> ${strLogFile}
    done
}

function errOutput
{
    typeset strLogFile=$1; shift
    typeset strLogID=$1; shift
    while IFS='' read -r strInput
    do
        >&2 echo "$(eval echo ${strLogID})${strInput}" && echo "$(eval echo ${strLogID})${strInput}" >> ${strLogFile}
    done
}

function main
{
    stdLogID="\<STD\>!"'$'"(date +\"%Y-%m-%d!%H:%M:%S\")!"
    errLogID="\<ERR\>!"'$'"(date +\"%Y-%m-%d!%H:%M:%S\")!"
    logFile=/tmp/out.log
    > $logFile

    exec 3>&1 1> >(stdOutput ${logFile} "${stdLogID}${FUNCNAME[0]}!")
    exec 4>&2 2> >(errOutput ${logFile} "${errLogID}${FUNCNAME[0]}!")

    >&2 echo "Line1"
    echo "Line2"
    >&2 echo "Line3"
    echo "Line4"
    >&2 echo "Line5"
    echo "Line6"
    >&2 echo "Line7"
    echo "Line8"
    >&2 echo "Line9"
    echo "Line10"

    exec 1>&3 3>&-
    exec 2>&4 4>&-
}
main
sync
exit

このスクリプトからどのような出力が必要ですか?他のすべての行にはERRが最初に表示され、次にSTDが表示され、行番号は1〜10の順序で配置されます。

<ERR>!2016-08-01!14:06:15!main!Line1
<STD>!2016-08-01!14:06:15!main!Line2
<ERR>!2016-08-01!14:06:15!main!Line3
<STD>!2016-08-01!14:06:15!main!Line4
<ERR>!2016-08-01!14:06:15!main!Line5
<STD>!2016-08-01!14:06:15!main!Line6
<ERR>!2016-08-01!14:06:15!main!Line7
<STD>!2016-08-01!14:06:15!main!Line8
<ERR>!2016-08-01!14:06:15!main!Line9
<STD>!2016-08-01!14:06:15!main!Line10

私が一般的に取得する出力タイプの例です。バッファリングのため、行番号が正しくありません。

<ERR>!2016-08-01!14:06:15!main!Line1
<STD>!2016-08-01!14:06:15!main!Line2
<STD>!2016-08-01!14:06:15!main!Line4
<ERR>!2016-08-01!14:06:15!main!Line3
<STD>!2016-08-01!14:06:15!main!Line6
<ERR>!2016-08-01!14:06:15!main!Line5
<STD>!2016-08-01!14:06:15!main!Line8
<ERR>!2016-08-01!14:06:15!main!Line7
<STD>!2016-08-01!14:06:15!main!Line10
<ERR>!2016-08-01!14:06:15!main!Line9

答え1

私の問題は、リダイレクトされた関数の外部で "echo"コマンドを処理することです。私がしたすべての初期試みは私の機能の範囲内でした。この問題を解決するために、すべてのエコー呼び出しをバッファリング解除し、その機能を使用したくないときに「コマンドエコー」を使用する新しい「エコー」機能を作成しました。これは明らかにechoコマンドのバッファリングを解除するだけです。テキストを出力する他の実行ファイルもバッファリングを引き起こす可能性があります。

#!/bin/bash

function stdOutput
{
    typeset strLogFile=$1; shift
    typeset strLogID=$1; shift
    while IFS='' read -r strInput
    do
    command echo "$(eval command echo ${strLogID})${strInput}" && command echo "$(eval command echo ${strLogID})${strInput}" >> ${strLogFile}
    done
}

function errOutput
{
    typeset strLogFile=$1; shift
    typeset strLogID=$1; shift
    while IFS='' read -r strInput
    do
    >&2 command echo "$(eval command echo ${strLogID})${strInput}" && command echo "$(eval command echo ${strLogID})${strInput}" >> ${strLogFile}
    done
}

function echo
{
    typeset strParameters=$@
    typeset strExecutable=$(which echo)
    unbuffer ${strExecutable} $@
}

function main
{
    stdLogID="\<STD\>!"'$'"(date +\"%Y-%m-%d!%H:%M:%S\")!"
    errLogID="\<ERR\>!"'$'"(date +\"%Y-%m-%d!%H:%M:%S\")!"
    logFile=/tmp/out.log
    > $logFile

    exec 3>&1 1> >(stdOutput ${logFile} "${stdLogID}"\$"{FUNCNAME[1]}!")
    exec 4>&2 2> >(errOutput ${logFile} "${errLogID}"\$"{FUNCNAME[1]}!")

    >&2 echo "Line1"
    echo "Line2"
    >&2 echo "Line3"
    echo "Line4"
    >&2 echo "Line5"
    echo "Line6"
    >&2 echo "Line7"
    echo "Line8"
    >&2 echo "Line9"
    echo "Line10"

    exec 1>&3 3>&-
    exec 2>&4 4>&-
}
main
sync
exit

関連情報