PIPE #3/3

다시 EOF를 처리하기 전으로 돌아가보자.

while True:
    name = input()
    print("Hello "+ name)

이걸 실행하면 아래와 같은 에러메세지가 출력된다는 것은 알 것이다.

$ echo "KHS" | python3 hello_multi.py
Hello KHS
Traceback (most recent call last):
  File "hello_multi.py", line 2, in <module>
    name = input()
EOFError: EOF when reading a line
$

출력된 결과를 기념삼아 파일로 바로 저장을 해보자.
표준출력을 파일로 담기 위해서는 > 리디렉션을 이용한다.

$ echo "KHS" | python3 p.py > out.txt
Traceback (most recent call last):
  File "hello_multi.py", line 2, in <module>
    name = input()
EOFError: EOF when reading a line
$

어? 에러메세지는 그냥 출력된다.

그럼 out.txt에는 뭐가 들어있나?

$ cat out.txt
Hello KHS
$

이럴수가 저게 뭔지 알고 내가 print()한 것만 저장을 했을까?

STDERR

여기서 >의 효능을 알아봐야한다. >는 STDOUT을 받아 다른 경로로 쓰는 명령이다.
에러메세지는 STDOUT이 아니라 STDERR로 출력되었기 때문에 화면으로 출력된 것이다.
|의 효능도 STDOUT을 STDIN으로 넘기는 것이지 STDERR을 넘기지 않는다!

STDOUT과 STDERR은 둘다 콘솔로는 출력되지만, 실제로는 서로 다른 레이어라고 생각하면 될 것 같다.

왜 출력방법을 두개로 뒀을까? STDOUT은 프로그램이 입력값에 의해 생산하는 의미 있는 데이터를 출력하는 용도이고,
STDERR은 디버깅과 운영을 위해서 필요한 진행정보를 출력하는 용도이다.

파이프로만 프로그램을 연결해서 쓰다보면 다음 파이프로 넘기면 안되지만 사람은 봐야하는 정보가 있기 마련이다.

막간 리디렉션 활용

>1>의 약자이다. 1은 STDOUT을 의미하고 2는 STDERR을 의미한다.

STDOUT과 STDERR을 서로 다른 파일에 저장하기

$ echo KHS | python3 hello_multi.py 1>out.txt 2>err.txt
$ cat out.txt
Hello KHS
$ cat err.txt
Traceback (most recent call last):
  File "hello_multi.py", line 2, in <module>
    name = input()
EOFError: EOF when reading a line
$

위와 같이 하면 STDOUT은 out.txt에 STDERR은 err.txt에 저장된다.
1과 2의 순서가 바뀌면 안되니 조심.

STDOUT과 STDERR을 한 파일에 같이 저장하기

$ echo KHS | python3 hello_multi.py 1>out.txt 2>&1
$ cat out.txt
Hello KHS
Traceback (most recent call last):
  File "hello_multi.py", line 2, in <module>
    name = input()
EOFError: EOF when reading a line
$

위와 같이하면 STDERR을 STDIN에다가 쓰는 거고 STDIN은 out.txt에 쓰는 것이 되어서,
첨에 생각했던대로 out.txt에 에러메세지까지 모두 저장된다.

crontab에서 자주 보는 구문

0 * * * * /where/is/script/run.sh >/dev/null 2>&1

crontab은 출력결과를 관리자 메일로 발송하므로 메세지를 전부 /dev/null로 보내서 소각(?)하면 조용히~ 실행한다.

다시 돌아와서

파이썬안에서 STDERR로 출력을 해보자.

print()와 sys.stderr 을 활용하는 방법 두가지가 있다.

print()

import sys
print("Hello Error", file=sys.stderr)

sys.stderr

import sys
sys.stderr.write("Hello Error\n")

확인 방법은 >를 써서 실행해보자.

$ python3 hello_error.py 1>out.txt 2>err.txt
$ cat out.txt
$ cat err.txt
Hello Error
$

파이프 끝~

STDIN, STDOUT, STDERR, EOF, 1>, 2>, | 가 무엇인지 한번 더 떠올려보자.