본문 바로가기
Tools2026년 7월 28일5분 읽기

셸 리다이렉션과 파일 디스크립터 — 2>&1이 뜻하는 것

YS
김영삼
조회 6
셸 리다이렉션과 파일 디스크립터 — 2>&1이 뜻하는 것

셸 리다이렉션은 프로그램의 입출력 스트림(표준입력·표준출력·표준에러)을 화면 대신 파일이나 다른 스트림으로 돌리는 문법이다. 핵심은 이 세 스트림이 각각 0, 1, 2라는 파일 디스크립터 번호를 가진다는 것, 그리고 >는 기본적으로 1번만 다룬다는 사실이다.

많은 사람이 2>&1을 부적처럼 붙이면서도 정확히 왜 그렇게 쓰는지는 모른다. 나도 한동안 그랬다. 순서를 바꿔 써서 로그가 통째로 날아간 뒤에야 원리를 제대로 팠다. 이 글은 그 원리를 정리한 것이다.

세 개의 스트림, 세 개의 번호

모든 유닉스 프로세스는 시작할 때 세 개의 표준 스트림을 물고 태어난다.

FD이름용도
0stdin입력 받기
1stdout정상 결과 출력
2stderr에러·진단 메시지

여기서 오해가 시작된다. ls foo > out.txt를 했는데 "그런 파일 없음" 에러는 여전히 화면에 뜬다. 왜? >1번(stdout)만 파일로 돌리기 때문이다. 에러는 2번(stderr)으로 나가서 그대로 터미널에 남는다. 정상 출력과 에러를 분리해 다루라고 유닉스가 일부러 채널을 나눠둔 것이다.

기본 리다이렉션 문법

문법의미
> fstdout을 f에 덮어쓰기
>> fstdout을 f에 이어쓰기
2> fstderr를 f로
< ff를 stdin으로
2>&1stderr를 stdout이 가리키는 곳으로

&가 붙은 2>&1이 관건이다. "2번을, 1번이 지금 가리키는 곳으로 복제하라"는 뜻이다. 여기서 순서가 생명이다.

순서를 틀리면 로그가 샌다

# 올바름: 1을 먼저 파일로, 그다음 2를 1과 같은 곳으로
cmd > out.txt 2>&1
# 틀림: 2를 먼저 (아직 터미널인) 1로 복제, 그 후 1만 파일로
cmd 2>&1 > out.txt   # ← stderr는 여전히 터미널로 샌다

리다이렉션은 왼쪽에서 오른쪽으로 순차 적용된다. 2>&1은 "그 시점에 1이 향하던 목적지"를 복사하는 것이라, 1을 아직 파일로 안 돌린 상태에서 이걸 쓰면 stderr가 터미널을 복제해버린다. 이 한 줄 때문에 나는 야간 배치의 에러 로그를 통째로 잃은 적이 있다.

Bash에는 이 실수를 막는 축약형이 있다.

cmd &> out.txt      # stdout+stderr 둘 다 out.txt로 (덮어쓰기)
cmd &>> out.txt     # 둘 다 이어쓰기

/dev/null과 스트림 분리

/dev/null은 무엇을 써도 삼켜버리는 블랙홀 장치다. 필요 없는 출력을 버릴 때 쓴다.

cmd 2> /dev/null          # 에러만 버리고 정상 출력은 유지
cmd > /dev/null 2>&1      # 전부 버림 (조용히 실행)
cmd 1> out.log 2> err.log # 정상과 에러를 각각 다른 파일로

마지막 예시처럼 채널을 분리해두면, 배치 작업에서 "에러 파일 크기가 0이 아니면 알림"같은 감시가 아주 쉬워진다. stderr가 따로 존재하는 이유가 바로 이거다.

히어독과 히어스트링

입력 쪽 리다이렉션도 알아두면 스크립트가 깔끔해진다.

# 히어독: 여러 줄을 stdin으로
cat <<EOF > config.ini
port = 8080
host = localhost
EOF
# 히어스트링: 한 줄을 stdin으로
grep foo <<< "$LINE"

자주 묻는 질문

2>&1과 &> 는 완전히 같나요?

결과만 보면 둘 다 stdout과 stderr를 같은 곳으로 보냅니다. 다만 &>Bash/Zsh의 축약 문법이라 목적지가 파일일 때만 쓰고, POSIX sh 호환이 필요하면 > f 2>&1을 써야 합니다. 또 파이프로 넘길 땐 |& 또는 2>&1 |를 씁니다.

>와 2>&1의 순서가 왜 중요한가요?

리다이렉션은 왼쪽부터 순서대로 적용되고, 2>&1은 그 순간 1번이 가리키는 목적지를 복사하기 때문입니다. 1번을 파일로 돌리기 전에 2번을 복제하면 stderr가 여전히 터미널을 가리켜 파일에 안 들어갑니다. 반드시 > f를 먼저 쓰세요.

출력이 파일엔 잘 들어가는데 화면에도 동시에 보고 싶어요.

리다이렉션만으로는 한 곳만 갑니다. 파일과 화면에 동시에 뿌리려면 tee를 쓰세요. 예: cmd 2>&1 | tee out.log. tee는 stdin을 받아 화면과 파일 양쪽에 복제해 씁니다.

>로 덮어쓰는 실수가 무서운데 방지책이 있나요?

Bash에서 set -o noclobber를 켜면 >로 기존 파일을 덮어쓰려 할 때 거부합니다. 정말 덮어써야 할 땐 >|로 강제할 수 있습니다. 중요한 데이터 파일을 다루는 스크립트에 넣어두면 사고를 크게 줄입니다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록