dup, dup2 이외에도 파일을 다루는 더 많은 정보와 예제를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.
https://reakwon.tistory.com/233
파일 서술자 복제 함수 dup, dup2
함수 이름에서도 알 수 있듯이 무엇을 복제한다는 함수입니다. 무엇을 복제할까요? 바로 파일 서술자(file descriptor)입니다. 함수 이름이 너무 심플하네요. 이 함수들을 사용하기 위해서는 <unistd.h>를 꼭 include해야합니다.
dup
#include <unistd.h>
int dup(int fd);
dup는 fd로 전달받은 파일 서술자를 복제하여 반환합니다. dup가 돌려주는 파일 서술자는 가장 낮은 서술자를 반환합니다. 성공시 새 파일 서술자, 오류시 -1을 반환합니다.
dup2
#include <unistd.h>
int dup2(int fd, int fd2);
dup2는 새 서술자의 값을 fd2로 지정합니다. 만일 fd2가 이미 열려있으면 fd2를 닫은 후 복제가 됩니다. 역시 성공시 새 파일 서술자, 오류시 -1을 반환합니다.
dup 예제
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
int main(void){
int fd1, fd2;
char message[32]={"message via fd2\n"};
fd1=open("made_by_fd1",O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
if(fd1<0){
printf("file open error\n");
exit(0);
}
fd2=dup(fd1);
write(fd2,message,strlen(message));
printf("fd1 :%d, fd2:%d\n",fd1,fd2);
close(fd1);
close(fd2);
}
파일 디스크립터 0, 1, 2는 이미 표준 입출력에 의해서 할당되어 있는 상태입니다.
위의 코드는 made_by_fd1이라는 파일을 열고 그 파일 디스크립터가 fd1에 할당됩니다. 그 후 fd1을 복제하여 나온 파일디스크립터를 fd2가 갖고 있게 됩니다.
그렇다면 write하여 fd2에 쓰면 어떻게 될까요?
아래의 그림을 참고하여 예측해봅시다.
예상하셨나요? fd2는 fd1 파일 서술자를 복제하였으니 made_by_fd1에 메시지를 기록하게 됩니다.
다음은 그 결과입니다. dup은 남아있는 파일 서술자 중 가장 작은 값을 내어주니 fd2가 4인것도 확인할 수 있네요.
# gcc dup_test.c
# ./a.out
fd1 :3, fd2:4
# cat made_by_fd1
message via fd2
dup2 예제
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
int main(void){
int fd1, ret;
char message[32]={"STDERR from fd1\n"};
//그림 1번
fd1=open("made_by_fd1",O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
if(fd1<0){
printf("file open error\n");
exit(0);
}
//표준 입출력으로 print됨
printf("file open\n");
//fd1의 파일 디스크립터가 명시한 STDOUT_FILENO의 파일 디스크립터로
//복제됨,
//그림 2번
ret=dup2(fd1,STDOUT_FILENO);
//fd1으로 출력됨
printf("fd1 :%d, ret:%d\n",fd1,ret);
//STDERR_FILENO 디스크립터가 명시된 fd1으로 복제됨
//그림 3번
ret=dup2(STDERR_FILENO,fd1);
//fd1은 에러로 출력됨
write(fd1,message,strlen(message));
//stdout이 file로 써짐
printf("printf를 썼지만 파일에 기록됨 \n");
close(fd1);
}
글로만 설명하는 것보다 이해하기 쉽도록 그림과 같이 설명해보도록 하겠습니다.
우선 여러분은 위 코드를 보고 왜 아래의 그림이 되는지 이해해보도록 해봅시다.
1. 우선 파일을 여는데 위의 예제와 같은 이름으로 파일을 엽니다. 그렇다면 fd1은 3이 되겠네요.
2. dup2로 STDOUT_FILENO라는 파일 서술자를 명시된 fd1로 바꿔버립니다. dup2를 조금 더 쉽게 이해하려면 두 번째인자가 첫 번째 인자로 가리키는 화살표 방향이 바뀐다라고 이해하시면 됩니다. 그리고 dup2는 성공적으로 호출이 되면 두 번째 인자의 값을 반환합니다. 실패시 -1을 반환하므로 에러 처리는 필수인데 저는 귀찮아서 하지 않았습니다.
printf는 표준 출력인데 printf로 문자열을 출력한다면 fd1으로 출력하는 것과 같습니다. 그러니까 우리가 만든 파일로 출력이 되겠네요.
3. 이제 fd1을 표준 에러로 redirect합니다. 방향을 바꿔버린다는 것이죠. 그렇게 되어 fd1으로 메시지를 출력하게 되면 표준 에러로 메시지를 출력하는 것과 같습니다.
이제 결과를 보도록할까요?
# gcc dup2_test.c
# ./a.out
file open
STDERR from fd1
# cat made_by_fd1
fd1 :3, ret:1
printf를 썼지만 파일에 기록됨
이상으로 dup, dup2에 대한 설명과 사용법을 예제를 통해 알아보았습니다. 이해하기 쉽도록 설명하려고 노력했는데 이해하셨는지 모르겠네요.
감사합니다.