FD 0 : stdin
FD 1 : stdout
FD 2 : stderr
명령 → stdout/stderr로 결과를 출력. 리다이렉션으로 이들을 파일이나 파이프로 보냄.
# stdout을 파일로 (덮어쓰기)
command > out.txt
# stdout을 파일에 추가(append)
command >> out.txt
# stderr을 파일로
command 2> err.txt
# stderr을 파일에 추가
command 2>> err.txt
# stdin을 파일로부터 읽기
command < input.txt
# stdout과 stderr를 같은 파일로 합치기 (포터블)
command > out_and_err.txt 2>&1
# 또는 (bash 전용 간단문법)
command &> out_and_err.txt
중요 — 순서가 중요
command > out 2>&1 : >가 먼저 수행되어 stdout이 파일로 향하고, 그 다음 2>&1로 stderr를 현재(바뀐) stdout으로 복제 → stderr도 파일로 들어감. (의도한 동작)
command 2>&1 > out : 먼저 stderr를 현재 stdout(터미널)으로 복제, 그 다음 stdout을 파일로 변경 → stderr는 여전히 터미널로 남음. 즉 서로 다른 결과.
항상 > file 2>&1 또는 2>file 1>&2 등 의도한 순서로 작성할 것.
# stdout은 그대로 콘솔에, stderr만 파일로
command 2> err.txt
# stdout을 파일로, stderr는 콘솔에 유지 (순서 중요)
command 2> /dev/tty > out.txt # 복잡하므로 보통 아래 방식 권장
# 추천: stdout만 파일, stderr는 터미널로 남겨두려면
command > out.txt # stderr 자동으로 콘솔에 남음
# (하지만 > out.txt 2>&1 would combine)
# 표준출력 무시
command > /dev/null
# 표준에러 무시
command 2> /dev/null
# 둘 다 무시
command > /dev/null 2>&1
# 또는 bash: command &> /dev/null
파이프 |는 한 명령의 stdout을 다음 명령의 stdin으로 보냄(주로 stdout만 전달 — stderr는 전달되지 않음).
cmd1 | cmd2
tee는 stdout을 파일로 쓰면서 다음 프로세스로도 전달:
cmd | tee logfile | other_cmd
# 출력 기록 + 파이프 계속
# 로그 파일에만 쓰려면:
cmd | tee logfile > /dev/null
Here-document: 여러 줄을 표준입력으로 제공
cat <<EOF > file.txt
line1
line2 $VARIABLE # 변수 확장됨
EOF
변수 치환을 막고 싶으면 'EOF'로 감싸기:
cat <<'EOF'
$VARIABLE # 그대로 출력
EOF
<<-EOF는 각 줄의 선행 탭을 제거(탭으로 들여쓰기된 스크립트에서 유용).
Here-string (bash/ksh):
grep pattern <<< "$variable"
명령의 출력을 파일처럼 취급(임시 FIFO 사용):
# diff 두 정렬된 파일 비교
diff <(sort fileA) <(sort fileB)
# 명령의 결과를 프로그램의 파일 인자로 전달
some_cmd >(process_output)
유용: 명령 간 비교·병렬 처리 시.
여러 명령을 하나의 파일로 리다이렉트하려면 brace {} 또는 subshell () 사용:
# 같은 셸에서 리다이렉트 (중괄호, 세미콜론 필요)
{ cmd1; cmd2; } > all_out.txt 2>&1
# 서브셸(별도 프로세스)
( cmd1; cmd2 ) > all_out.txt 2>&1
중괄호는 현재 셸에서 실행되며 } 앞에 공백 필요.
스크립트 전체의 출력을 로그 파일로 보내려면:
exec > script.log 2>&1
# 이후 이 셸에서 실행되는 모든 명령의 stdout/stderr가 script.log로 감.
원래 stdout 저장하고 복원:
exec 3>&1 # FD 3에 원래 stdout 저장
exec > out.txt # stdout을 파일로 바꿈
# ... 작업 ...
exec >&3 3>&- # stdout 복원, FD 3 닫기
FD 숫자(3,4 등)는 임의로 사용 가능(0..2는 표준).
FD 닫기:
exec 3>&- # FD 3 닫음
# 현재 stdout을 FD 3에 저장
exec 3>&1
# stdout을 파일로 리다이렉트
exec 1>out.log
# 이 시점에서 명령들
echo "this goes to out.log"
# 잠깐 원래 stdout(터미널)에 쓰기
echo "to terminal" >&3
# 복원
exec 1>&3 3>&-
sudo는 리다이렉션 자체는 셸(사용자 권한)에서 처리하기 때문에 sudo로 명령만 root로 실행해도 > /root/file 같은 리다이렉션은 권한 부족 에러가 날 수 있습니다.
해결법:
# 1) sudo sh -c 'command > /root/file'
sudo sh -c 'echo hello > /root/somefile'
# 2) 또는 tee 사용
echo hello | sudo tee /root/somefile > /dev/null
command > out.txt 2> err.txt
혹은 시간 순서를 보존하려면 stdbuf나 unbuffer로 버퍼링 조정(파이프를 통해 순서가 섞일 수 있음).
순서 실수: command 2>&1 > out 은 의도대로 작동하지 않음(위 참조).
권한 문제: sudo로 실행해도 >는 여전히 비루트 셸에서 수행 → sudo sh -c 또는 tee 사용.
버퍼링으로 인한 출력 순서 변경: 파이프나 파일로 리다이렉션하면 stdout/stderr 버퍼링이 달라져 출력 순서가 바뀔 수 있음. stdbuf -oL 등으로 라인 버퍼링을 강제하거나 unbuffer 사용.
&>는 bash 전용: POSIX 호환성을 원하면 >file 2>&1 사용.
스크립트 전체를 로그로 남기기:
#!/bin/bash
exec > >(tee -a /var/log/myscript.log) 2>&1
# 이렇게 하면 stdout은 파일과 터미널에 동시에 쓰임, stderr도 합쳐서 둘 다로
echo "start"
# rest of script
안전한 백그라운드 실행(로그 보존):
nohup myscript.sh > /var/log/myscript.out 2>&1 &
mkfifo /tmp/myfifo로 FIFO 생성 후 producer/consumer를 연결 가능:
mkfifo /tmp/f
# in one shell:
cat /tmp/f | process_consumer
# in another shell:
echo "data" > /tmp/f
> : stdout → 파일(덮어쓰기)
>> : stdout → 파일(추가)
< : stdin ← 파일
2> : stderr → 파일
&> : stdout+stderr → 파일 (bash 전용)
>file 2>&1 : stdout → file, stderr → same as stdout (포터블)
command | command : stdout 파이프 전달
cmd | tee file : stdout을 file과 파이프 둘 다로
<<EOF : here-document (여러 줄 stdin)
<(cmd) : process substitution (파일처럼 사용)