** 본인이 직접 작성한 글입니다. 외부 공유시 반드시 출처를 명시하여 주세요.

 

Unix/Linux 계열 시스템은 일반 파일, 디렉토리, 소켓, 파이프, 블록 디바이스, 캐릭터 디바이스등을 모두 파일로 관리한다. 그리고 각 프로세스가 이러한 파일 자원에 접근할 때는 파일 디스크립터라는 개념을 이용하게 된다. 참고로 윈도우에는 핸들이라는 유사한 개념이 있다.

시스템 내부적으로 현재 오픈되어 있는 파일들의 리스트를 테이블 형태로 관리하게 되며 파일 디스크립터는 FD 테이블 내 각 파일의 인덱스 값과 같다. 그리고 이 인덱스 값은 0과 양수 형태의 값을 갖게 된다.

표준 입력 및 출력도 파일 디스크립터로 표현된다. 이들은 미리 정의된 값을 갖는다.

  • Standard Input (표준 입력) -> 파일 디스크립터 0번, STDIN_FILENO
  • Standard Output (표준 출력) -> 파일 디스크립터 1번, STDOUT_FILENO
  • Standard Error (표준 에러 출력) -> 파일 디스크립터 2번, STDERR_FILENO

위 내용은 unistd.h 파일에서 확인할 수 있다.

/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */

각 프로그램에서 파일 디스크립터를 참조할 때는 0, 1, 2와 같은 번호를 사용할 수도 있지만 가급적 unistd.h에 정의된 POSIX 이름(STDIN_FILENO 등)을 쓰는 것이 좋다.

참고로 혹시 다음과 같은 구문을 본 적이 있는가?

$ ./test.sh > /dev/null 2>&1

2> : 표준 에러 출력을,
&1 : 1번 표준 출력 파일 디스크립터가 참조하고 있는 곳으로 보낸다는 뜻이다.

그러면 간단한 테스트 소스를 통해 확인해보자.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main (int *argc, char **argv) {
        int fd;
        fd = creat("/root/fdTest.txt", 0644);

        if (fd == -1) {
                printf ("File Descriptor Error !!\n");
        } else {
                printf ("File Descriptor : %d\n", fd);
        }
}

실행 결과는 다음과 같다.

# ./fdTest1
File Descriptor : 3