exec를 사용하여 모든 후속 명령의 stderr를 리디렉션하십시오.


42

모든 출력을 하나의 파일, 디버그 로그 및 터미널로 리디렉션 해야하는 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
일부 쉘에서는에 |&대한 바로 가기로 작동 2>&1 |하며 적어도 약간 더 편리합니다.
Kevin

답변:


39

많은 명령을 한 번에 리디렉션하는 솔루션은 다음과 같습니다.

#!/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

명령을 실행하면이 환경이 상속됩니다. 명령을 실행하여 티에 파이프하면 명령 환경은 다음과 같습니다.

stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file

따라서 명령의 표준 오류는 여전히 셸이 표준 오류로 사용하는 방식으로 진행됩니다.

실제로 심볼 링크의 내용을 나열하는 데 /proc/[pid]/fd사용 ls -l하여 명령의 환경을 볼 수 있습니다 . 0여기 의 파일은 표준 입력이고 1표준 출력이며 2표준 오류입니다. 명령이 더 많은 파일을 열면 (대부분의 프로그램에서) 파일도 볼 수 있습니다. 프로그램은 또한 표준 입력 / 출력 및 재사용을 재 또는 종료를 선택할 수 0, 12.


40

스크립트 맨 위에서 다음과 같은 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
이것은 bashism을 사용합니다-다른 쉘 (예 : 대시)에서는 작동하지 않을 수 있습니다. 그러나 질문에 bash, +1이 지정되었으므로.
Richard Hansen

8
@RichardHansen, 프로세스 대체는 bash가 아닌 ksh에 의해 도입 된 기능이며 zsh에서도 지원되므로 bashism 이라고하지 않습니다 .
Stéphane Chazelas

6
@StephaneChazelas : 당신은 좋은 지적을합니다. POSIX 표준에서 구문을 지원하지 않으므로 /bin/sh스크립트 에서 보편적으로 작동하지 않습니다 (많은 사람들이 /bin/sh스크립트 에서 bash 구문을 잘못 사용함 ).
Richard Hansen

나에게 이것은 /dev/fd/62: Operation not supported단서가 있습니까?
Eun

1
로그 파일을 제외하고 stderr를 리디렉션하지 않는 방법이 있습니까? 원본 스크립트가 myscript있고 내가 실행 하더라도 ./myscript > /dev/null여전히 bye어떤 스크립트가 나오는지 볼 수 있습니다 echo bye >&2.
Martin Jambon

0

stderr 및 stdout을 파일에 쓰고 화면에 stderr을 표시하십시오 (stdout에서).

exec 2> >(tee -a -i "$HOME/somefile.log")
exec >> "$HOME/somefile.log"

크론에 유용하므로 우편으로 오류 (및 오류 만)를받을 수 있습니다

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