로그 파일 및 콘솔에 출력 쓰기


99

유닉스 쉘에서 나는 (A ENV 파일이 ENV 파일은 파일, 데이터베이스 연결 정보 등을 기록하는 로그 파일의 이름과 경로, 리디렉션 출력 및 오류 등 사용자 스크립트를 실행하는 데 필요한 매개 변수를 정의합니다 () 모든 출력을 리디렉션하는 에코 메시지를 ) 및 다음 코드를 사용하여 실행 된 스크립트의 로그 파일에 오류가 있습니다.

exec 1>>${LOG_FILE}
exec 2>>${LOG_FILE}

env 파일은 각 스크립트의 시작 부분에서 실행됩니다. env 파일의 위 코드로 인해 사용자 출력 또는 오류 일 수있는 모든 콘솔 출력이 실제로 필요한 로그 파일에 직접 출력됩니다.

그러나 콘솔과 로그 파일 모두에 표시하려는 선택적 사용자 출력이 있습니다. 그러나 위의 코드 때문에 그렇게 할 수 없습니다.

위의 코드를 제거하면이 경우에 원하는 결과를 얻을 수 있지만 다른 모든 출력을 로그 파일에 수동으로 작성해야하는 것은 쉬운 일이 아닙니다.

위의 코드를 제거하지 않고 콘솔과 로그 파일 모두에서 출력을 얻는 방법이 있습니까?

답변:


106
exec 3>&1 1>>${LOG_FILE} 2>&1

stdout 및 stderr 출력을 로그 파일로 보내지 만 fd 3이 콘솔에 연결된 상태로 두어도됩니다.

echo "Some console message" 1>&3

콘솔에만 메시지를 쓰거나

echo "Some console and log file message" | tee /dev/fd/3

콘솔 로그 파일 모두 에 메시지를 쓰려면 - 출력을 자체 fd 1 (여기서는 )과 작성하도록 지시 한 파일 (여기서는 fd 3, 즉 콘솔)로 보냅니다 .teeLOG_FILE

예:

exec 3>&1 1>>${LOG_FILE} 2>&1

echo "This is stdout"
echo "This is stderr" 1>&2
echo "This is the console (fd 3)" 1>&3
echo "This is both the log and the console" | tee /dev/fd/3

인쇄 할 것이다

This is the console (fd 3)
This is both the log and the console

콘솔에 넣고

This is stdout
This is stderr
This is both the log and the console

로그 파일에.


2
제안한대로 작동했습니다. 그러나 나는 tee / dev / fd / 3 이해하지 못했습니다 . 그 티가 파일 및 콘솔 로그 메시지를 기록 알지만 정확히 이해하지 못했다 는 / dev / FD / 3 티 후 사용
abinash 쉬 레스타

@shrestha 그것은 티의 비정상적인 사용입니다, 동의합니다. 는 /dev/fd/3그래서, "현재 열려있는 전략 중 3"을 참조하는 파일 이름 tee /dev/fd/31 전략 중 자사의 표준 입력에 도착하는대로 쓰기도 3 (디스크립터합니다 /dev/fd/3파일). Fd 1은 로그 파일에 연결되고 fd 3은 콘솔에 연결됩니다.
Ian Roberts

또한 콘솔 시도가 아닌 파일에만 쓰기를 원합니다. echo "blah" | tee file1.txt | tee file2.txt >/dev/null 'Blah'는 file1.txt 및 file2.txt에 저장되지 않고 콘솔에 기록되지 않습니다.
danger89

이것은 저에게 매우 도움이되었습니다. 주제에서 벗어난 것을 발견했지만 여러분 중 일부는 그 이유를 알고있을 것입니다. bash 스크립트에서 R 스크립트를 실행하고 있습니다. 다양한 R 함수의 콘솔 출력은 색상이 지정됩니다 (내가 정의한대로). 위의 접근 방식을 사용하여 출력을 콘솔 및 로그 파일로 리디렉션 할 때 콘솔 출력은 더 이상 색상이 지정되지 않습니다. 그 이유는 무엇일까요?
dieHellste

1
@dieHellste 일부 프로그램은 출력이 tee터미널로 직접 이동하지 않고 다른 프로세스 (이 경우 터미널에 기록 )로 파이프되는시기를 감지 하고 일치하도록 출력을 조정할 수 있습니다.
Ian Roberts

43

예, 다음을 사용합니다 tee.

tee-표준 입력에서 읽고 표준 출력 및 파일에 쓰기

다음과 같이 명령을 tee에 파이프하고 파일을 인수로 전달하십시오.

exec 1 | tee ${LOG_FILE}
exec 2 | tee ${LOG_FILE}

이것은 둘 다 출력을 STDOUT에 인쇄하고 동일한 출력을 로그 파일에 기록합니다. 자세한 내용은를 참조하십시오 man tee.

이것은 로그 파일에 stderr를 쓰지 않으므로 두 스트림을 결합하려면 다음을 사용하십시오.

exec 1 2>&1 | tee ${LOG_FILE}

2
위의 솔루션이 작동하지 않았습니다. redirect.env 파일이 다음과 같이 있습니다. ##### redirect.env ###### export LOG_FILE = log.txt exec 1 2> & 1 | 티 -a $ {LOG_FILE} exec 1 | 티 -a $ {LOG_FILE} exec 2 | tee -a $ {LOG_FILE} ######### 및 작업 파일에는 다음 코드가 포함되어 있습니다. ##### output.sh ##### #! / bin / sh. redirect.env echo "유효한 출력"ech "잘못된 출력"#############하지만 오류가 발생합니다 : #### redirect.env : line 3 : exec : 1 : not found redirect.env : 줄 5 : exec : 1 : 찾을 수 없음 redirect.env : 줄 6 : exec : 2 : 찾을 수 없음 #### 및 로그 파일에서도 동일한 오류가 발생합니다. 내가 뭘 잘못하고 있니?
abinash shrestha

댓글에서 새 줄이 제거되어 있기 때문에 말하기가 매우 어렵습니다. 요점 과 같은 곳에 코드 붙여 넣기를 추가 할 수 있습니까?
Jon Cairns

1
UnixRedirect 링크에 파일을 추가했습니다 . 관련 파일은 redirect.env 및 output.sh 있습니다
abinash 쉬 레스타

1
이 코드는 작동하지 않는 것 같습니다 (적어도 더 이상). 당신은 보통 얻을 것입니다script.sh: line 5: exec: 1: not found
tftd

39

나는 Joonty의 대답을 시도했지만

exec : 1 : 찾을 수 없음

오류. 이것은 나에게 가장 잘 작동하는 것입니다 ( zsh에서도 작동하도록 확인 되었습니다).

#!/bin/bash
LOG_FILE=/tmp/both.log
exec > >(tee ${LOG_FILE}) 2>&1
echo "this is stdout"
chmmm 77 /makeError

이후의 /tmp/both.log 파일에는

this is stdout
chmmm command not found 

tee에서 -a를 제거하지 않으면 /tmp/both.log가 추가됩니다.

힌트 : >(...)프로세스 대체입니다. 그것은을 할 exec받는 사람 tee이 파일 인 것처럼 명령.


1
이것은 나에게 매력처럼 작동했지만 다른 답변은 맞거나 놓쳤습니다.
제이 테일러

이 스 니펫을 공유해 주셔서 감사합니다. 이것은 다른 답변과 비교할 때 잘 작동하는 것 같습니다!
tftd 2016

이것은 작동하지만 이제 내 쉘은 실행 후 다릅니다.
Josh Usre

당신이 어떤 도움이 필요하거나 다른 SO-사용자를 돕고 싶다면 @JoshUsre는 다른 무엇인지 설명하고, 쉘, 버전을 설명해주십시오 OS 등
alfonx

1
stdout과 stderr를 구분할 필요가없는 경우 문을 exec > >(tee ${LOG_FILE}) 2>&1.
darkdragon

5

타임 스탬프와 함께 stdout 및 로그 파일에 로그를 표시하고 싶었습니다. 위의 답변 중 어느 것도 나를 위해 일하지 않았습니다. 내가 사용했다 공정 대체간부 명령을하고 다음 코드를 함께했다. 샘플 로그 :

2017-06-21 11:16:41+05:30 Fetching information about files in the directory...

스크립트 상단에 다음 줄을 추가합니다.

LOG_FILE=script.log
exec > >(while read -r line; do printf '%s %s\n' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done)
exec 2> >(while read -r line; do printf '%s %s\n' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done >&2)

이것이 누군가를 돕기를 바랍니다!


.... 개발 운영 팀에 도움이되도록하는 것이 가능 호스트 디렉토리에 로그인하는 모든 응용 프로그램 오류를 기록하는 것입니다
프라 사드 Shinde에게

3

로그 파일의 경우 날짜를 입력하여 텍스트 데이터를 입력 할 수 있습니다. 다음 코드가 도움이 될 수 있습니다.

# declaring variables

Logfile="logfile.txt"   
MAIL_LOG="Message to print in log file"  
Location="were is u want to store log file"

cd $Location   
if [ -f $Logfile ]  
then   
echo "$MAIL_LOG " >> $Logfile

else        

touch $Logfile   
echo "$MAIL_LOG" >> $Logfile    

fi  

출력 : 2. 로그 파일은 첫 번째 실행에서 생성되고 다음 실행에서 계속 업데이트됩니다. 향후 실행시 로그 파일이 누락 된 경우 스크립트는 새 로그 파일을 생성합니다.


1

원하는 출력을 얻는 방법을 찾았습니다. 다소 비 정통적인 방법 일 수 있지만. 어쨌든 여기에 있습니다. redir.env 파일에는 다음 코드가 있습니다.

#####redir.env#####    
export LOG_FILE=log.txt

      exec 2>>${LOG_FILE}

    function log {
     echo "$1">>${LOG_FILE}
    }

    function message {
     echo "$1"
     echo "$1">>${LOG_FILE}
    }

그런 다음 실제 스크립트에는 다음 코드가 있습니다.

#!/bin/sh 
. redir.env
echo "Echoed to console only"
log "Written to log file only"
message "To console and log"
echo "This is stderr. Written to log file only" 1>&2

여기서 에코 오직 콘솔 출력 로그 만 로그 파일에 출력 메시지 로그 파일 및 본체 모두에 출력한다.

위의 스크립트 파일을 실행 한 후 다음과 같은 출력이 나타납니다.

콘솔에서

콘솔
에서 콘솔에만 반향 됨
콘솔 및 로그로

로그 파일의 경우

로그 파일 에서 로그 파일에만 기록됨
이것은 stderr입니다. 로그 파일에만 작성
콘솔 및 로그에

이 도움을 바랍니다.


1

이것을 시도하면 작업이 수행됩니다.

log_file=$curr_dir/log_file.txt
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)

이것은 exec > >(tee -a ${log_file} )내 필요에 완벽하게 작동합니다. 위의 이전 솔루션은 실패한 경우 강제 종료하는 스크립트의 일부를 중단합니다. 감사합니다
MitchellK

1
    #
    #------------------------------------------------------------------------------
    # echo pass params and print them to a log file and terminal
    # with timestamp and $host_name and $0 PID
    # usage:
    # doLog "INFO some info message"
    # doLog "DEBUG some debug message"
    # doLog "WARN some warning message"
    # doLog "ERROR some really ERROR message"
    # doLog "FATAL some really fatal message"
    #------------------------------------------------------------------------------
    doLog(){
        type_of_msg=$(echo $*|cut -d" " -f1)
        msg=$(echo "$*"|cut -d" " -f2-)
        [[ $type_of_msg == DEBUG ]] && [[ $do_print_debug_msgs -ne 1 ]] && return
        [[ $type_of_msg == INFO ]] && type_of_msg="INFO " # one space for aligning
        [[ $type_of_msg == WARN ]] && type_of_msg="WARN " # as well

        # print to the terminal if we have one
        test -t 1 && echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg"

        # define default log file none specified in cnf file
        test -z $log_file && \
            mkdir -p $product_instance_dir/dat/log/bash && \
                log_file="$product_instance_dir/dat/log/bash/$run_unit.`date "+%Y%m"`.log"
        echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg" >> $log_file
    }
    #eof func doLog

0

stdout과 stderr를 로그 파일에 추가하는 것이 매우 유용하다는 것을 알았습니다. exec > >(tee -a)를 사용하여이 작업을 수행하는 방법이 궁금했기 때문에을 사용하여 alfonx의 솔루션을 보게되어 기뻤습니다 exec. here-doc 구문을 사용하는 창의적인 솔루션을 발견했습니다 .. /unix/80707/how-to-output-text-to-both-screen-and-file-inside-a-shell -스크립트

zsh에서 here-doc 솔루션은 stdout / stderr 및 로그 파일 모두에 출력을 복사하기 위해 "multios"구성을 사용하여 수정할 수 있음을 발견했습니다.

#!/bin/zsh
LOG=$0.log
# 8 is an arbitrary number;
# multiple redirects for the same file descriptor 
# triggers "multios"
. 8<<\EOF /dev/fd/8 2>&2 >&1 2>>$LOG >>$LOG
# some commands
date >&2
set -x
echo hi
echo bye
EOF
echo not logged

exec솔루션 만큼 읽기 쉽지는 않지만 스크립트의 일부만 기록 할 수 있다는 장점이 있습니다. 물론 EOF를 생략하면 전체 스크립트가 로깅과 함께 실행됩니다. zshmultios를 구현 하는 방법을 잘 모르겠지만 tee. 불행히도 exec.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.