/home/caml-shaving

리-다이렉션

저리 가라

2018-10-30

태그: dev think

분석 시간 관련 이슈를 파기 위해 빌드에 최소 8분, 최대 50분 정도 걸리는 패키지들을 빌드해보고 있었다. 빌드 도중에 떨어지는 부가 데이터와 각각 패키지들의 빌드 시간도 기록할겸 대충 time build_cmd > log 때리고 퇴근했다. 그런데 오늘 와서 보니 log 파일에는 빌드 관련 로그만 잔뜩 남아있고 time 커맨드의 실행 결과는 터미널에만 남아있는 것이 아닌가? 당연히 시간도 남을 거라 생각해서 좀 당황했지만 관련 내용을 찾아보니 금방 이유를 찾을 수 있었다.

결론부터 말하면 time 커맨드를 쓰지말고 \time 커맨드와 -v , -o filename 옵션을 이용해서 시간과 메모리 사용량 모두 파일에 쓰고 광명을 찾는 것이 좋다.

time 커맨드

man 페이지를 보면 다음 설명이 있다.

DESCRIPTION

time run the program COMMAND with any given arguments ARG…. When COMMAND finishes, time displays information about resources used by COMMAND (on the standard error output, by default). If COMMAND exits with non-zero status, time displays a warning and the exit status.

주목해야 하는 부분은 on the standard error output, by default이다. 즉 time 커맨드의 결과는 stdout이 아니라 stderr에 쓰이고 있었던 것이다. (man 페이지 읽는 습관을 생활화합시다…)

리다이렉션

링크의 내용 중 일부를 발췌해왔다.

유닉스 쉘의 i/o stream은 다음과 같다.

핸들 이름 설명
0 stdin Standard input
1 stdout Standard output
2 stderr Standard error

예를 들어, command1 2> file1command1을 실행하고, 표준 에러 스트림을 file에다 쓰게 된다. csh 계열의 쉘에서는 i/o 스트림을 구분하기 위해 숫자 앞에 &를 붙이는데, 이유는 1이라는 파일과 표준 출력 1을 구분하기 위해서다. 그래서 cat file 2>1의 경우는 stderr이 1이라는 이름의 파일에 리다이렉트되고, cat file 2>&1의 경우는 stderr이 stdout에 리다이렉트된다.

또하나 쓸만한 것은 표준 파일 핸들을 다른 파일로 리다이렉트 하는 것이다. 가장 유명한 건 역시 stderr를 stdout에 합쳐서 에러메시지를 같이 처리하는 일이다. 예를 들어, find / -name .profile > results 2>&1 커맨드는 파일이름이 .profile인 모든 파일을 찾아서 그 결과를 result 파일에다 쓴다. 리다이렉션 없이 실행하면, 찾은 건 stdout에 출력하고 에러(예를 들면, 보호된 디렉토리를 탐색하려고 할때 발생하는 권한 오류)는 stderr에 출력한다. 즉, stdout이 results 파일에 출력되는 반면, 에러메시지는 그냥 콘솔에 출력되는 것이다. 찾은 것과 에러 메시지 둘 다 results 파일에다 쓰고 싶으면, 2>&1을 이용해서 stderr(핸들 2)를 stdout(핸들 1)에 합치면 된다.

만약에 합친 출력을 파이프로 다른 프로그램에 던져 주고 싶으면, 2>&1로 머지한 시퀀스가 파이프에 넘겨 주기 전에 앞서야 한다. 즉, find / -name .profile 2>&1 | less 꼴이 되야 한다.

command > file 2>&1은 다음과 같이 해석하면 된다. 먼저 표준 출력(command의 정상 실행 결과)이 file로 리다이렉트된다. 그리고 stderr이 추가적으로 stdout 핸들로 리다이렉트되는데, 이때 이미 stdout은 file로 리다이렉트된 상황이다. 따라서 최종적으로 command의 실행 결과와 오류가 모두 file에 쓰여진다.