dup2()
dup2()는 한 파일 디스크립터(oldfd)에 연결된 커널 오브젝트를 다른 FD(newfd) 슬롯에도 연결시키는 함수이다. 보통은 리다이렉션을 구현할 때 많이 사용한다.
함수 원형
#include <unistd.h>
int dup2(int oldfd, int newfd);
- oldfd : 복사할 원본 FD
- newfd : 덮어쓸 대상 FD
- 반환 값 : 성공 시 newfd, 실패 시 -1
newfd가 이미 열려 있다면 먼저 close(newfd)가 내부적으로 호출하고 newfd가 oldfd와 같은 커널 오브젝트를 가르키도록 덮어쓰기 된다.
동작 원리
모든 프로세스는 각자 자신만의 파일 디스크립터(FD) 테이블을 가지고 있다. 그리고 프로세스가 시작될 때 운영체제는 이 FD 테이블을 다음과 같이 초기화한다.
0번 FD → /dev/tty (stdin)
1번 FD → /dev/tty (stdout)
2번 FD → /dev/tty (stderr)
그래서 우리가 printf("hi");를 호출하면 C 라이브러리(glibc)는 내부적으로 버퍼를 처리한 뒤 write(1, "hi", 2); 같은 시스템 콜을 호출하고, 1번 FD가 현재 세션 터미널 장치 드라이버의 커널 객체를 가리키고 있기 때문에 최종적으로 터미널 화면에 "hi"가 출력되는 구조이다.
이 상태에서 프로세스에서 새 파일을 열면 보통 FD 테이블의 가장 낮은 빈 슬롯인 3번에 연결된다. 예를 들어, 아래 코드가 실행되면 FD 3번은 "out.txt"라는 파일의 커널 오브젝트를 가리키게 된다.
int fd = open("out.txt", O_WRONLY|O_CREAT);
이후 dup2(3, 1)을 실행하면 close(1)을 먼저 호출하고, fd 3번이 가리키는 커널 오브젝트를 1번 슬롯에도 연결된다.
dup2(3, 1);
결과적으로 FD 테이블은 아래와 같이 바뀐다.
0번 FD → /dev/tty (stdin)
1번 FD → out.txt
2번 FD → /dev/tty (stderr)
3번 FD → out.txt
이제 printf("hi")를 호출하면 내부적으로 write(1, "hi", 2)가 실행되며, 출력은 터미널이 아니라 out.txt 파일에 기록된다.
예시 코드
- stdout을 파일로 리다이렉션하는 예시
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("output.log", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("open");
return 1;
}
// 표준 출력을 파일로 리다이렉션
if (dup2(fd, STDOUT_FILENO) == -1) {
perror("dup2");
return 1;
}
close(fd); // fd는 더 이상 필요 없음
// 이제 printf는 터미널이 아니라 output.log에 기록됨
printf("This message goes to the file.\n");
return 0;
}
- 자식 프로세스 표준 입출력을 리다이렉션하는 예시
pid_t pid = fork();
if (pid == 0) { // child
int dn = open("/dev/null", O_WRONLY);
if (dn < 0) { perror("open /dev/null"); _exit(1); }
// stdout, stderr을 /dev/null로 리다이렉션
dup2(dn, STDOUT_FILENO);
dup2(dn, STDERR_FILENO);
close(dn);
// 이제 어떤 출력도 터미널에 안 보임
execlp("ls", "ls", "-l", NULL);
perror("execlp");
_exit(127);
}
else {
wait(NULL);
}
참고로 부모, 자식이 각각 자기 파일 디스크립터 테이블을 갖고 있으니까, 자식 프로세스에서만 dup2를 하면 부모의 표준 출력에는 영향이 없다.
'프로그래밍 > 리눅스 시스템 프로그래밍' 카테고리의 다른 글
| Linux ] rename이 atomic한 이유 (리눅스 파일의 참조 구조) (0) | 2025.11.24 |
|---|---|
| Linux ] 파일 append는 정말 atomic 할까? (0) | 2025.11.12 |
| Linux ] fork()를 통한 프로세스 생성 (0) | 2025.11.01 |
| Linux에서 현재 프로세스가 모니터가 연결된 GUI 세션인지 확인하는 법 (0) | 2025.10.24 |
| POSIX C ] root 권한 체크하기 (0) | 2025.10.21 |