모든 출력을 파일, 디버그 로그 및 터미널로 리디렉션해야 하는 bash 파일이 있습니다. 스크립트의 모든 명령을 디버깅하고 기록하려면 stdout 및 stderr을 리디렉션해야 합니다.
2>&1 | tee -a $DEBUG
파일의 모든 명령에 대해 추가하고 싶지 않습니다 . 나는 와 함께 살 수 있다 | tee -a $DEBUG
.
비슷한 것으로 이것을 할 수 있는 방법이 있었던 것으로 기억합니다 exec 2>&1
.
현재 나는 다음과 같은 것을 사용하고 있습니다.
#!/bin/bash
DEBUGLOG=/tmp/debug
exec 2>&1
somecommand | tee -a $DEBUGLOG
somecommand2 | tee -a $DEBUGLOG
somecommand3 | tee -a $DEBUGLOG
하지만 작동하지 않습니다. 누구든지 해결책이 있거나 이유를 설명할 수 있습니까?
답변1
다음과 같이 스크립트 상단에서 exec를 사용할 수 있습니다.
exec > >(tee "$HOME/somefile.log") 2>&1
예를 들어:
#!/bin/bash -
exec > >(tee "$HOME/somefile.log") 2>&1
echo "$HOME"
echo hi
date
date +%F
echo bye 1>&2
다음과 같이 파일 $HOME/somefile.log
과 터미널로 출력하겠습니다.
/home/saml
hi
Sun Jan 20 13:54:17 EST 2013
2013-01-20
bye
답변2
한 번에 많은 수의 명령을 리디렉션하는 솔루션은 다음과 같습니다.
#!/bin/bash
{
somecommand
somecommand2
somecommand3
} 2>&1 | tee -a $DEBUGLOG
원래 솔루션이 작동하지 않는 이유: exec 2>&1은 표준 오류 출력을 콘솔에서 스크립트를 실행하는 경우 콘솔이 되는 쉘의 표준 출력으로 리디렉션합니다. 명령에 대한 파이프 리디렉션은 명령의 표준 출력만 리디렉션합니다.
관점에서 보면 somecommand
, 표준 출력은 연결된 파이프로 들어가고 tee
, 표준 오류는 쉘의 표준 오류와 동일한 파일/의사 파일로 들어가며, 쉘의 표준 출력으로 리디렉션됩니다. 플랫폼에서 프로그램 실행에서 제어할 수 있습니다.
이를 설명하는 한 가지 실제 방법은 실제로 무슨 일이 일어나고 있는지 살펴보는 것입니다.
터미널에서 셸을 실행하면 원래 환경은 다음과 같을 수 있습니다.
stdin -> /dev/pts/42
stdout -> /dev/pts/42
stderr -> /dev/pts/42
표준 오류를 표준 출력( exec 2>&1
)으로 리디렉션한 후 기본적으로 아무것도 변경하지 않습니다. 그러나 스크립트의 표준 출력을 파일로 리디렉션하면 다음과 같은 환경이 됩니다.
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /dev/pts/42
그러면 쉘 표준 오류를 표준 출력으로 리디렉션하면 다음과 같이 됩니다.
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /your/file
명령을 실행하면 이 환경이 상속됩니다. 명령을 실행하고 이를 tee로 파이프하면 명령 환경은 다음과 같습니다.
stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file
따라서 명령의 표준 오류는 여전히 표준 오류로 쉘에 전달됩니다.
/proc/[pid]/fd
:use를 보면 실제로 명령 환경을 볼 수 ls -l
있으며 심볼릭 링크의 내용도 나열할 수 있습니다. 여기에 있는 파일은 0
표준 입력, 1
표준 출력 2
및 표준 오류입니다. 명령이 더 많은 파일을 열면(대부분의 프로그램이 수행함) 해당 파일도 볼 수 있습니다. 프로그램은 표준 입력/출력 을 리디렉션하거나 닫고 이를 재사용하도록 선택할 수도 있습니다 0
.1
2
답변3
stderr 및 stdout을 파일에 쓰고 stderr를 화면에 표시합니다(stdout에서).
exec 2> >(tee -a -i "$HOME/somefile.log")
exec >> "$HOME/somefile.log"
cron에 유용하므로 메일을 통해 오류(및 오류만)를 받을 수 있습니다.
답변4
매뉴얼 script
페이지에는 몇 가지 경고가 있습니다.
비대화형 셸에서 스크립트를 실행하는 것은 권장되지 않습니다. 스크립트의 내부 셸은 항상 대화형이므로 예기치 않은 결과가 발생할 수 있습니다.
또한 스크립트는 예상보다 더 많은 입력을 읽을 수 있으므로 명령 파이프라인에서 스크립트를 사용하지 않아야 합니다.
script
표준 입력 및/또는 표준 출력이 리디렉션될 때 사용하는 것은 안전하지 않다고 생각합니다.
명령을 실행할 때 다음을 수행합니다.
output=$("<command> <args>" 2> tee -a $LOGFILE >&2)
OP는 모든 명령에 대해 정확히 동일한 작업을 수행하기를 원하지 않지만 함수를 쉽게 정의할 수 있다는 것을 이해합니다.
run () { ... output=$("$(@) 2> tee -a $LOGFILE >&2"; ... }
이를 통해 일반 출력을 캡처하고 처리하는 동시에 경고 및 오류를 기록하고 동시에 stderr에 표시할 수 있습니다.
그럼 당신은 할 수 있습니다
[ $? -eq 0 ] && echo "<command> <args> succeeded! Output:\n$output\n(EOF)" >>$LOGFILE
원하는 경우 일반 출력도 기록할 수 있습니다.