programing

stdout의 COPY를 bash 스크립트 자체에서 로그 파일로 리다이렉트

muds 2023. 4. 16. 15:55
반응형

stdout의 COPY를 bash 스크립트 자체에서 로그 파일로 리다이렉트

stdout을 파일로 리디렉션하는 방법을 알고 있습니다.

exec > foo.log
echo test

이렇게 하면 foo.log 파일에 '테스트'가 저장됩니다.

이제 출력을 로그 파일로 리다이렉트하여 stdout에 저장합니다.

즉, 스크립트 외부에서 3회 실행할 수 있습니다.

script | tee foo.log

스크립트 자체에서 선언하고 싶다.

나는 노력했다.

exec | tee foo.log

하지만 그것은 작동하지 않았다.

#!/usr/bin/env bash

# Redirect stdout ( > ) into a named pipe ( >() ) running "tee"
exec > >(tee -i logfile.txt)

# Without this, only stdout would be captured - i.e. your
# log file would not contain any error messages.
# SEE (and upvote) the answer by Adam Spiers, which keeps STDERR
# as a separate stream - I did not want to steal from him by simply
# adding his answer to mine.
exec 2>&1

echo "foo"
echo "bar" >&2

은 「」인 것에 주의해 주세요.bash 아니라, 이에요.sh. 를 " "로 로 기동합니다.sh myscript.shsyntax error near unexpected token '>'.

하고 있는 는, 「」를 하는 합니다.tee -i 시 위한 ( to James)Thomas Moon1979년).


에 쓰느냐에 (「Tool」ls예를 들어 색상 및 열화된 출력을 사용하여 위 구성을 파이프에 출력한다는 의미로 탐지합니다.

"/"/"컬럼화ls -C --color=always이렇게 하면 색상 코드도 로그 파일에 기록되므로 읽기 어려워집니다.

승인된 답변은 STDERR을 개별 파일 기술자로 유지하지 않습니다.즉,

./script.sh >/dev/null

하지 .bar 그리고 까지.

./script.sh 2>/dev/null

다 됩니다.foo ★★★★★★★★★★★★★★★★★」bar터미널에 접속합니다.그것은 일반 사용자가 예상할 수 있는 행동이 아닌 것이 분명하다.은, 같은 파일에 되는, 할 수 .이러한 프로세스는, 「」 「TE」 「TE」 「TE」 「TE」 「TE」 「TE」 「TE」 「TE」입니다.

#!/bin/bash

# See (and upvote) the comment by JamesThomasMoon1979 
# explaining the use of the -i option to tee.
exec >  >(tee -ia foo.log)
exec 2> >(tee -ia foo.log >&2)

echo "foo"
echo "bar" >&2

(상기에서는 로그파일이 처음에 잘리는 것은 아닙니다.이 동작을 하고 싶은 경우는, 로그 파일을 추가할 필요가 있습니다.

>foo.log

스크립트 맨 위로 이동합니다.)

의 POSIX.1-2008 사양에서는 출력이 버퍼링되지 않은 것, 즉 회선 버퍼링되지 않은 것이 요구되기 때문에 이 경우 STDOUT과 STDERR이 같은 회선에 도달하는 경우가 있습니다.foo.log단, 단말에서도 발생할 수 있기 때문에 로그파일은 단말기에서 볼 수 있는 을 정확하게 반영하고 있습니다.STDOUT 행을 STDERR 행에서 완전히 분리할 경우 로그파일을 2개 사용하는 것을 검토해 주십시오.각 행에 날짜 스탬프 프레픽스를 붙이면 나중에 시간순으로 재구성할 수 있습니다.

busybox, macOS bash 및 non-bash 쉘용 솔루션

받아들여진 답변은 확실히 bash에게 최선의 선택이다.bash에 할 수 bash를 .비지박스 배쉬exec > >(tee log.txt)구문을 사용합니다., 「」는 .exec >$PIPE지정된 파이프와 같은 이름의 일반 파일을 생성하려고 하는데, 이 파일이 실패하여 중단됩니다.

이것이 배쉬가 없는 다른 사람에게 유용하기를 바란다.

명명된 파이프를 합니다.rm $PIPEVFS에서 파이프의 링크가 해제되지만 VFS를 사용하는 프로세스는 완료될 때까지 파이프의 참조 카운트를 유지합니다.

$*의 사용이 반드시 안전한 것은 아닙니다.

#!/bin/sh

if [ "$SELF_LOGGING" != "1" ]
then
    # The parent process will enter this branch and set up logging

    # Create a named piped for logging the child's output
    PIPE=tmp.fifo
    mkfifo $PIPE

    # Launch the child process with stdout redirected to the named pipe
    SELF_LOGGING=1 sh $0 $* >$PIPE &

    # Save PID of child process
    PID=$!

    # Launch tee in a separate process
    tee logfile <$PIPE &

    # Unlink $PIPE because the parent process no longer needs it
    rm $PIPE    

    # Wait for child process, which is running the rest of this script
    wait $PID

    # Return the error code from the child process
    exit $?
fi

# The rest of the script goes here

스크립트 파일 내에서 다음과 같이 모든 명령을 괄호 안에 넣습니다.

(
echo start
ls -l
echo end
) | tee foo.log

bash 를 syslog.bash로 할 수 .은, 「 쪽인가」, 「어느 쪽인가」를 통해서도 할 수 있습니다./var/log/syslog를 통해 stderr. syslog를 포함한 메타데이터가 됩니다.

맨 위에 다음 행을 추가합니다.

exec &> >(logger -t myscript -s)

또는 로그를 다른 파일로 전송합니다.

exec &> >(ts |tee -a /tmp/myscript.output >&2 )

에는 「」가 필요합니다.moreutils)ts타임스탬프가 추가됩니다).

수락된 답변을 사용하여 스크립트는 예외적으로 일찍('exec > > (tee...)' 직후) 반환되고 나머지 스크립트는 백그라운드에서 실행됩니다.그 솔루션을 내 방식대로 사용할 수 없었기 때문에 문제에 대한 다른 해결책/해결책을 찾았습니다.

# Logging setup
logfile=mylogfile
mkfifo ${logfile}.pipe
tee < ${logfile}.pipe $logfile &
exec &> ${logfile}.pipe
rm ${logfile}.pipe

# Rest of my script

이를 통해 스크립트 출력은 프로세스에서 파이프를 통해 모든 것을 디스크 및 스크립트의 원래 stdout에 기록하는 'tee'의 하위 백그라운드 프로세스로 전송됩니다.

'exec & >'는 stdout과 stderr를 모두 리다이렉트하므로 필요에 따라 개별적으로 리다이렉트하거나 stdout을 원할 경우 'exec >'로 변경할 수 있습니다.

스크립트의 선두에서 파이프가 파일시스템에서 삭제되어도 프로세스가 완료될 때까지 계속 기능합니다.rm-line 뒤에 있는 파일 이름을 사용하여 참조할 수 없습니다.

Bash 4에는 명령어에 대한 명명된 파이프를 확립하고 이를 통해 통신할 수 있는 명령어가 있습니다.

이그제큐티브를 기반으로 한 솔루션이 마음에 들지 않는다고는 말할 수 없습니다.저는 Tee를 직접 사용하는 것을 선호하기 때문에 요청 시 스크립트 자체를 Tee로 호출합니다.

# my script: 

check_tee_output()
{
    # copy (append) stdout and stderr to log file if TEE is unset or true
    if [[ -z $TEE || "$TEE" == true ]]; then 
        echo '-------------------------------------------' >> log.txt
        echo '***' $(date) $0 $@ >> log.txt
        TEE=false $0 $@ 2>&1 | tee --append log.txt
        exit $?
    fi 
}

check_tee_output $@

rest of my script

이를 통해 다음과 같은 작업을 수행할 수 있습니다.

your_script.sh args           # tee 
TEE=true your_script.sh args  # tee 
TEE=false your_script.sh args # don't tee
export TEE=false
your_script.sh args           # tee

이를 사용자 정의할 수 있습니다. 예를 들어, tee=false를 기본값으로 만들거나, TEE가 로그 파일을 대신 유지하도록 하는 등입니다.이 솔루션은 jbarlow의 솔루션과 비슷하다고 생각합니다만, 간단하게 말하면, 아직 경험하지 못한 한계가 있을지도 모릅니다.

둘 다 완벽한 솔루션은 아니지만, 다음은 시도해 볼 수 있는 몇 가지 방법입니다.

exec >foo.log
tail -f foo.log &
# rest of your script

또는

PIPE=tmp.fifo
mkfifo $PIPE
exec >$PIPE
tee foo.log <$PIPE &
# rest of your script
rm $PIPE

스크립트에 때 파일이 있는 로 유지되며,가 될 수도 수도 가 되지 않을 수도 있습니다).이것은 문제가 될 수도 있고 아닐 수도 있습니다(즉, 문제가 될 수도 있습니다).rm중중부부부부부셸셸셸셸셸나 。

언급URL : https://stackoverflow.com/questions/3173131/redirect-copy-of-stdout-to-log-file-from-within-bash-script-itself

반응형