본문 바로가기
프로그래밍/리눅스 시스템 프로그래밍

Linux ] dup2() 함수를 사용한 표준입출력 리다이렉션

by eteo 2025. 11. 3.
반응형

 

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를 하면 부모의 표준 출력에는 영향이 없다.

 

 

반응형