출력 리디렉션으로 버퍼링 방지

출력 리디렉션으로 버퍼링 방지

기본적으로 모든 출력을 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

관련 정보