Linux/Bash 셸에는 명령을 실행할 때 활용할 수 있는 세 가지 데이터 스트림이 있습니다. 바로 stdin(표준 입력), stdout(표준 출력), stderr(표준 에러)입니다. 이 글에서는 이들의 개념과 사용 방법을 자세히 알아보겠습니다.
stdin, stdout, stderr는 콘솔에 텍스트를 표시하고, 각 스트림에서 출력되는 데이터를 다른 프로그램으로 전달할 수 있게 해줍니다.
이것들을 통칭하여 표준 스트림(Standard Streams)이라고 부릅니다.
stdin(표준 입력)이란?
텍스트 입력 스트림입니다.
애플리케이션은 stdin을 통해 텍스트를 입력으로 받을 수 있습니다.
stdout(표준 출력)이란?
프로그램의 텍스트 출력 스트림입니다.
애플리케이션은 stdout을 통해 데이터를 다른 프로그램으로 보내거나, 콘솔에 표시하여 사용자가 확인할 수 있게 합니다.
stderr(표준 에러)란?
프로그램의 오류 출력 스트림입니다.
프로그램 실행 중 오류가 발생하면, 해당 오류 정보는 일반 출력과 구분되어 stderr 스트림을 통해 전달되어야 합니다.
…그래서 실제로 무슨 의미일까요?
컴퓨터 프로그램은 입력과 출력 데이터를 가지고 작업을 수행합니다. 예를 들어, 어떤 프로그램은 수학 방정식을 입력받아 그 해답을 제공할 수 있습니다.
방정식을 프로그램 안으로 넣고(IN), 답을 프로그램 밖으로 꺼내는(OUT) 방법이 필요합니다. 또한 방정식을 풀 수 없는 경우를 파악해야 하므로, 다른 일반 출력과 분리된 형태로 오류(ERROR) 메시지를 확인하고 싶을 것입니다.
바로 이것이 stdin, stdout, stderr입니다.
모든 것이 같은 방식으로 동작하면 편리하기 때문에, 이러한 입력·출력·오류 스트림은 표준화되었고, 커맨드 라인용으로 만들어진 애플리케이션들은 모두 동일한 방식으로 동작합니다.
그래서 이름이 표준 스트림(Standard Streams)인 것입니다. 각 스트림에는 0부터 2까지의 숫자 식별자가 할당되어 있습니다:
| 번호 | 스트림 |
|---|---|
| 0 | stdin |
| 1 | stdout |
| 2 | stderr |
Bash/셸에서 stdin, stdout, stderr 리디렉션 및 파이핑하기
여러분이 Linux 셸에 타이핑하는 것도 하나의 텍스트 스트림입니다. 입력한 텍스트가 콘솔 입력으로 흘러들어가는 것입니다.
애플리케이션이 실행되면, 그로부터 출력되는 텍스트 데이터가 콘솔로 전달되어 화면에 표시됩니다.
이것이 콘솔에서 작업할 때의 기본 동작이지만, 얼마든지 변경할 수 있습니다. 스트림은 리디렉션(redirection)될 수 있습니다. 예를 들어, 프로그램의 출력을 화면 대신 파일로 직접 보낼 수 있습니다.
한 프로그램의 출력을 다른 프로그램의 입력으로 직접 연결하는 것도 가능합니다.
다음은 리디렉션과 파이핑의 기본적인 예제입니다.
리디렉션(Redirection)
일반적으로 echo 명령은 텍스트를 콘솔에 출력합니다:
echo "hello there!"
echo 프로그램의 stdout은 기본 경로를 따라 여러분의 화면에 표시됩니다.
리디렉션을 사용하면 이 출력을 다른 곳으로 보낼 수 있습니다. 아래 예제에서는 파일로 보냅니다:
echo "hello there!" > test.txt
test.txt라는 파일이 생성되며 그 안에 "hello there!"라는 텍스트가 저장됩니다 (주의: 이미 같은 이름의 파일이 존재하면 기존 내용이 덮어써집니다).
> 대신 >>를 사용하면 기존 파일을 덮어쓰지 않고 내용을 추가(append)할 수 있습니다.
이번에는 <를 사용해 stdin을 리디렉션해 보겠습니다.
cat < test.txt
cat 명령은 test.txt의 내용을 자신의 stdin 스트림으로 읽어 들인 후, cat 명령이 원래 하도록 설계된 대로 전달받은 데이터를 stdout으로 출력합니다. 기본적으로 stdout은 콘솔이므로, 결과적으로 hello there!가 화면에 출력됩니다.
파일의 데이터가 cat 명령의 stdin으로 전달된 것입니다. 즉, 리디렉션된 것입니다.
사실 이것은 약간 반칙입니다. cat 명령은 파이프 없이도 인자로 전달된 파일명을 읽으려고 시도하기 때문입니다. 하지만 이 예제의 목적상 가장 단순한 명령이기 때문에 사용했습니다.
하나의 명령에서 stdin과 stdout을 동시에 리디렉션할 수도 있습니다:
cat < test.txt > output.txt
stdin이 리디렉션되어 test.txt가 cat 프로그램으로 읽혀 들어가고, cat 프로그램의 stdout은 output.txt라는 파일로 향합니다.
역시 이것은 사실상 cat 명령으로 파일을 복사하는 것에 불과하지만, 다른 명령어를 추가로 설명할 필요 없이 간단히 보여줄 수 있는 좋은 예제입니다.
마지막으로, 고유한 스트림 번호를 지정하여 stderr 스트림을 리디렉션할 수 있습니다 (stdout은 기본값이므로 번호를 지정하지 않아도 됩니다):
cat nofile.txt 2> error.txt
stderr는 숫자 2로 식별됩니다. cat이 오류를 발생시키면, 그 오류는 이 스트림을 통해 error.txt 파일로 전달됩니다.
위 예제는 cat 명령이 nofile.txt 파일을 찾지 못했기 때문에, 다음 내용이 담긴 error.txt 파일을 생성합니다:
cat: nofile.txt: No such file or directory
동시 리디렉션
위 예제에서 stderr 스트림은 숫자 식별자로 지정되었습니다. 즉, 어떤 스트림을 리디렉션할지 번호로 지정함으로써 하나의 명령에서 stdout과 stderr를 동시에 리디렉션할 수 있습니다:
echo "hello there!" 1>test.txt 2>error.txt
위 명령에서 stdout은 test.txt로, stderr는 error.txt로 전송됩니다.
파이핑(Piping)
파이핑은 리디렉션과 유사하지만, stdin과 stdout만 다루며 오류(stderr)는 무시됩니다.
echo "hello there!" | cat
여기서 파이프(|)는 echo 명령의 stdout을 cat 명령의 stdin으로 연결(리디렉션)합니다.
결론
커맨드 라인 애플리케이션은 처음에는 직관적이지 않게 느껴질 수 있지만, 작업 자동화에 있어 매우 강력한 도구입니다. stdin, stdout, stderr — 이 표준 스트림들이 바로 이러한 유연성의 초석입니다. 명령들을 사슬처럼 연결하여 거의 모든 작업을 처리할 수 있는 복잡한 워크플로우를 손쉽게 만들 수 있습니다.