bash 스크립트 자체에서 stdout COPY를 로그 파일로 리디렉션
stdout 을 파일 로 리디렉션 하는 방법을 알고 있습니다.
exec > foo.log
echo test
이것은 'test'를 foo.log 파일에 넣습니다.
이제 출력을 로그 파일로 리디렉션하고 stdout에 유지하려고합니다.
즉, 스크립트 외부에서 사소하게 수행 할 수 있습니다.
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.sh
의 행을 따라 오류가 발생합니다 syntax error near unexpected token '>'
.
신호 트랩으로 작업하는 tee -i
경우 신호가 발생하는 경우 출력 중단을 피하기 위해이 옵션을 사용할 수 있습니다 . (의견에 대해 JamesThomasMoon1979에게 감사합니다.)
파이프 또는 터미널에 ls
쓰는지 여부에 따라 출력을 변경하는 도구 ( 예 : 색상 및 열화 된 출력 사용)는 위의 구성을 파이프로 출력하는 것을 의미합니다.
색상 화 / 컬럼 화를 시행하는 옵션이 있습니다 (예 :) ls -C --color=always
. 이로 인해 색상 코드가 로그 파일에도 기록되어 읽기 어려워 집니다.
허용 된 답변은 STDERR을 별도의 파일 설명 자로 유지하지 않습니다. 그 의미는
./script.sh >/dev/null
bar
터미널에 출력되지 않고 로그 파일에만 출력 됩니다.
./script.sh 2>/dev/null
터미널 foo
과 bar
터미널 모두에 출력됩니다 . 분명히 그것은 일반 사용자가 기대하는 행동이 아닙니다. 동일한 로그 파일에 추가되는 두 개의 별도 티 프로세스를 사용하여이 문제를 해결할 수 있습니다.
#!/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 사양tee(1)
이 출력 버퍼링이 필요하다, 즉 심지어 라인 버퍼링 그래서 STDOUT 및 STDERR가 동일한 행에 끝낼 수있다이 경우에 foo.log
; 그러나 이는 터미널에서도 발생할 수 있으므로 로그 파일은 터미널의 정확한 미러가 아닌 경우 터미널에서 볼 수 있는 내용을 충실히 반영 합니다. STDOUT 행을 STDERR 행과 완전히 분리하려면 나중에 각 시간에 날짜 소인 접 두부가있는 두 개의 로그 파일을 사용하여 나중에 시간순으로 다시 어셈블 할 수 있습니다.
busybox, macOS bash 및 비 -bash 쉘을위한 솔루션
수락 된 답변은 bash에 가장 적합한 선택입니다. bash에 액세스하지 않고 Busybox 환경에서 작업하고 있으며 exec > >(tee log.txt)
구문을 이해하지 못합니다 . 또한 exec >$PIPE
명명 된 파이프와 동일한 이름을 가진 일반 파일을 만들려고하면 제대로 작동 하지 않아 실패하고 중단됩니다.
바라건대 이것은 bash가없는 다른 사람에게 유용 할 것입니다.
또한 명명 된 파이프를 사용하는 사람 rm $PIPE
은 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에 만드는 쉬운 방법. 스크립트 출력은 /var/log/syslog
stderr를 통해 또는 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
이렇게하면 스크립트의 출력이 프로세스에서 파이프를 통해 'tee'의 하위 백그라운드 프로세스로 이동하여 모든 것을 디스크와 스크립트의 원래 stdout에 기록합니다.
'exec &>'는 stdout과 stderr을 모두 리디렉션하므로 원하는 경우 별도로 리디렉션하거나 stdout을 원하면 'exec>'로 변경할 수 있습니다.
스크립트 시작시 파이프가 파일 시스템에서 제거 되더라도 프로세스가 완료 될 때까지 계속 작동합니다. rm 행 다음에 파일 이름을 사용하여 참조 할 수 없습니다.
Bash 4에는 coproc
명령에 대한 명명 된 파이프를 설정하고이를 통해 통신 할 수있는 명령이 있습니다.
exec를 기반으로 한 솔루션에 익숙하다고 말할 수는 없습니다. 나는 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가 대신 로그 파일을 보유하도록하십시오.
이들 중 어느 것도 완벽한 솔루션은 아니지만 다음은 시도해 볼 수있는 몇 가지 사항입니다.
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
나중에 부모 셸에서 파일 을 작성할 수 있음).
'Programing' 카테고리의 다른 글
N 분마다 오프셋을 더한 Cron 작업 실행 (0) | 2020.04.21 |
---|---|
무료 XML 형식 도구 (0) | 2020.04.21 |
Go에서 JSON 포스트 요청 처리 (0) | 2020.04.21 |
BigDecimal이 0보다 큰 경우 비교 (0) | 2020.04.21 |
JavaScript 함수의 기본 인수 값 (0) | 2020.04.21 |