왜 gcc에서 '>'오류 메시지를 리디렉션하지 않습니까?


9

new.c에 다음 프로그램을 저장했습니다.

int main() 
{ 
    a;
    return 0; 
}

오류 메시지를 반환합니다. 이 메시지를 파일로 보내려고합니다. 그래서 나는 다음 명령을 사용했다

gcc new.c > temp.txt

그러나 여전히 터미널에서 출력을 얻었습니다. 우분투 13.04를 사용하고 있습니다. 어떻게 작동시킬 수 있습니까?


답변:


16

로 프로그램을 컴파일 할 때 gcc다양한 출력 유형이 있습니다 : to stdoutstderr. 일반적으로 >stdout스트림을 파일 printf("hello world\n");로 보냅니다 (예 : a의 결과 가로 전송 됨 stdout). 그러나 " stderr계속 설명해야 할 예외"로 가정되기 때문에 계속 화면으로 전송됩니다.

stderr를 파일로 재지 정하는 방법이 있습니다. 다음과 같은 (매우 직관적이지 않은) 명령으로이를 수행하십시오.

gcc new.c &> myFile

어디 &>"리디렉션 모든 것을"에 대한 "bash는 속기"입니다. @CharlesDuffy가 지적했듯이 POSIX 호환 양식은

gcc new.c > myFile 2>&1

"이 수단 컴파일 'new.c'및 전송 stdoutmyFile. 그리고 전송 stderr과 같은 장소 (2) stdout( &1표준 출력과 같은 장소"=) ".

서로 다른 리디렉션에 대한 자세한 내용은 http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.htmlhttp://mywiki.wooledge.org/BashFAQ/055 에서 확인할 수 있습니다 .

그건 그렇고, 프로그램 내에서 특별히 무언가를 보내려면 stderr다음과 같이하면됩니다.

fprintf(stderr, "hello world - this is urgent.\n");

프로그램에 포함시킨 경우 프로그램을 실행하고 "정상"출력을 파일로 보내면 여전히 콘솔에 나타납니다. 따라서 위의 내용을 실행 파일로 컴파일하면 urgent다음을 입력하십시오.

./urgent > /dev/null

콘솔에서 출력이 화면에 나타납니다.


2
mywiki.wooledge.org/BashFAQ/055 는 아마도 리디렉션에 대한 더 나은 소개 일 것입니다. 또한 실제로 POSIX 호환 양식 ( >myFile 2>&1)과 bash 확장 ( &>)을 소개해야합니다.
Charles Duffy

@CharlesDuffy-아주 좋은 점. 나는 완성도에 대한 답변에 그것들을 포함시킬 것이다.
Floris

11

때문에 >리디렉션 만 표준 출력 및 오류가 기록됩니다 stderr, 당신은 대신 다음 중 하나를 사용해야합니다 :

gcc new.c &> temp.txt ## redirect both stdout and stderr using bash or zsh only

...또는...

gcc new.c >temp.txt 2>&1 ## redirect both stdout and stderr in any POSIX shell

&>BASH 확장 은 파일 stdoutstderr파일을 모두 리디렉션 합니다. 그렇지 않으면 가장 쉬운 방법은 먼저 stdout ( >temp.txt)을 리디렉션 한 다음 stderr (FD 2)를 stdout (FD 1)에서 이미 리디렉션 된 파일 핸들의 복사본으로 만드는 것 2>&1입니다.


4

다른 사람들이 말했듯이 리눅스는 두 가지 다른 출력 스트림을 제공합니다.

stdout 또는 "표준 출력"은 모든 일반 출력이가는 곳입니다.
              파일 디스크립터를 사용하여이를 참조 할 수 있습니다 1.

stderr 또는 "표준 오류"는 대역 외 정보를위한 별도의 스트림입니다.
              파일 디스크립터를 사용하여이를 참조 할 수 있습니다 2.

왜 두 개의 다른 출력 스트림입니까? 가상 명령의 파이프 라인을 고려하십시오.

 decrypt $MY_FILE | grep "secret" | sort > secrets.txt

이제 decrypt명령이 실패하고 오류 메시지가 생성 된다고 가정하십시오 . 이 메시지를 (으 stdout)로 보낸 경우 파이프로 전송되며 "비밀"이라는 단어가 없으면이를 볼 수 없습니다. 따라서 무엇이 잘못되었는지 전혀 모르는 빈 출력 파일로 끝납니다.

그러나 파이프는 만 캡처하기 stdout때문에 decrypt명령은에 오류를 보낼 수 stderr있으며 콘솔에 오류 가 표시됩니다.

당신은 리디렉션 할 수 있습니다 stdoutstderr중 하나를 함께 또는 독립적으로 :

# Send errors to "errors.txt" and output to "secrets.txt"
# The following two lines are equivalent, as ">" means "1>"
decrypt $MY_FILE 2> errors.txt > secrets.txt
decrypt $MY_FILE 2> errors.txt 1> secrets.txt

오류를 리디렉션하여 stdout정상 출력 인 것처럼 처리 할 수 있습니다 .

# The operation "2>&1" means "redirect file descriptor 2 to file
# descriptor 1. So this sends all output from stderr to stdout.
# Note that the order of redirection is important.
decrypt $MY_FILE > errors.txt 2>&1 

# This may be confusing.  It will store the normal output in a file
# and send error messages to stdout, where they'll be captured by 
# the pipe and then sorted.
decrypt $MY_FILE 2>&1 > output.txt | sort

또한 재하는 "속기"표기법을 사용할 수 있습니다 모두 같은 파일을 표준 출력 및 표준 오류 :

decrypt $MY_FILE &> output.txt

마지막으로, >연산자는 출력 파일을 쓰기 전에 먼저 잘라냅니다 . 대신 기존 파일에 데이터를 추가 하려면 >>연산자를 사용하십시오 .

decrypt $MY_FILE 2>> more_errors.txt >> more_secrets.txt
decrypt $MY_FILE >> more_output.txt 2>&1

1
두 가지 퀴즈 : (1) 인용 부호가없는 매개 변수 확장 ( $FOO)을 사용하는 것이 일반적인 버그의 원인이며 예제에서 설명하는 것은 그리 좋지 않습니다. (2) 모든 대문자 변수 이름을 사용하는 것이 환경 및 내장 변수 (대문자로 대문자)와 로컬 변수 (대소 문자로 소문자) 간의 네임 스페이스 충돌의 주요 원인입니다. (3) >>파일을 한 번 열고 여러 명령에서 사용하기 위해 파일 디스크립터를 열어 두지 않고 사람들이 반복적으로 사용하도록 (명령에 사용될 때마다 파일을 다시 열 도록) 권장 하는 것은 비효율적 인 코드입니다.
찰스 더피

... 마지막 요점과 비교 : exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Charles Duffy

+1 정직하게 해주셔서 감사합니다, @CharlesDuffy. 모든 좋은 점. exec실제로는 일반적으로 더 나은 전략이지만 간단하게하기 위해 의도적으로 생략 했습니다.

또한, 붕괴 될 수 또는 (스페이스 전 및 후에이 있어야 여기서 , 및 전과 ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man, 'Reinstate
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.