Linux - Bash 쉘에서 표준 오류 재지정: File Descriptor의 의미를 잘 모르겠습니다.

조회수 1934회

이용약관을 읽어봤는데 스택오버플로우처럼 질문에 관련된 사항이 없어서 리눅스에 관련된 질문이지만 해봅니다.

리눅스 커맨드라인 완벽 입문서 (The Linux Command Line: Complete Introduction)의 번역본을 읽던 도중, 표준 오류 재지정 (Standard Error Redirection)이라는 부분이 나왔는데, 파일 디스크립터가 의미하는 게 뭔지를 잘 모르겠습니다. 다음은 책의 내용입니다:

표준 오류를 재지정할 때는 리다이렉션 연산자가 필요 없다. 다만, 파일 디스크립터를 참조한다. 프로그램은 번호로 지정된 파일 스트림 중에 어디에라도 출력을 할 수 있다. 우리는 앞서 표준 입출력과 표준 오류를 참조하였는데, 쉘은 내부적으로 이들을 각각 0, 1, 2번 파일 디스크립터로 표현한다. 쉘은 파일 디스크립터 번호를 이용해서 재지정할 수 있는 표기를 지원한다. 표준 오류는 파일 디스크립터 2와 같기 때문에 표준 오류를 재지정할 때 이 표기법을 사용할 수 있다:

[me@linuxbox ~]$ ls -l /bin/usr 2> ls-error.txt

파일 디스크립터 2는 리다이렉션 연산자 바로 앞에 위치하고 ls-error.txt 파일에 표준 오류 메시지를 보낸다.

이해가 안되는 부분은,

"다만, 파일 디스크립터를 참조한다. 프로그램은 버호로 지정된 파일 스트림 중에 어디에라도 출력을 할 수 있다."와, "쉘은 내부적으로 이들을 각각 0, 1, 2번 파일 디스크립터로 표현한다."입니다.

  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • 시스템 프로그래밍에 대해서 배우시면 곧 이해하는데 도움이 될 것 같습니다.

    파일 디스크립터는 유닉스(리눅스)의 커널에서, 프로세스가 다루고 있는 파일들을 관리하기 위해 사용하는 개념입니다. 표준 C에서는 FILE 구조체를 이용해서 다룹니다만, 시스템 프로그래밍에서는 운영체제가 제공하는 커널이 제공하는 개념을 사용합니다. 유닉스(리눅스)운영체제에서는 프로세스가 파일을 열면 이 파일 핸들을 관리하기 위해서 식별자를 부여하며, 이는 정수값을 지닙니다. 즉, 유닉스(리눅스)에서는 open하여 사용하고 있는 파일에 대한 식별자(일련번호)를 파일 디스크립터라고 하고, 이 파일 디스크립터는 각각의 프로세스마다 독립적입니다.

    파일 디스크립터에 대한 자세한 정보는 커널 내부에 존재하고, 프로세스에서는 이 파일 디스크립터 번호를 통해서, 파일(혹은 네트워크 소켓 등의 I/O)에 대한 입출력을 처리합니다.

    일단, 모든 프로세스는 3개의 파일 스트림을 항상 열고 있습니다. 하나는 키보드로 부터 입력 받기 위한 스트림으로 표준 입력입니다. 그리고 다른 두개는 표준 출력과 표준 에러 출력입니다. 지금 말씀 드린 순서대로 파일 디스크립터가 할당되는데, 0,1,2 순으로 할당되게 되어있습니다.

    쉘에서 ls 라고 실행하게 되면, ls라는 프로그램 코드를 실행하는 프로세스가 리눅스 커널에 만들어질 테고, 이 프로세스는 앞서 말한바대로, 기본적으로 0,1,2 파일 디스크립터를 사용하고 있는 상태가 됩니다.

    쉘에서는 이러한 파일 스트림에 대한 기본설정을 다른 파일 스트림으로 덮어쓰기할 수 있는 리다이렉션이나 파이프와 같은 기능이 있습니다.

    ls > ls.txt 라고 하면, ls프로세스의 표준출력, 즉 1번 파일 디스크립터를 화면에 출력하는 것이 아닌, ls.txt라는 파일로 출력하게 리다이렉션합니다.

    마찬가지로, ls 2> ls-error.txt라고 하면, ls프로세스에서 표준 에러 출력으로 출력인 2번 파일 디스크립터를 화면이 아닌, ls-error.txt라는 파일로 출력하도록 리다이렉션합니다.

    주: > 기호로 리다리렉션을 처리하는 것은 쉘의 기능입니다.

    추가답변

    모든 프로세스는 3개의 파일 스트림을 열고 있는 이유...

    • 몇 가지 다양한 설명이 가능합니다만, 가장 기본적인 설명만 하면, 우리가 사용하는 입출력 장치 중에 프로그램과 상호작용을 위한 인터페이스는 전통적으로 콘솔 출력(텍스트)와 키입력입니다. (나중에 윈도우 개념이 도입되면서, 포인팅 입력 장치 - 마우스, 그래픽 출력 장치 등이 추가됩니다만..., 전통적으로는 콘솔과 키입력입니다.)
    • 이 콘솔과 키입력은 프로세스와는 별개로 항상 사용하고 있는 장치에 해당합니다. ls같은 프로그램을 실행하기 전에 이미 사용하고 있는 장치입니다. 상호작용을 위한 장치는 운영체제에 의해서 이미 open되어 활성화 및 초기화하가 된 상태입니다. 이 장치를 프로세스가 따로 활성화하여 초기화한다는 것 자체가 더 이상하다고 봐야겠지요.
    • 그래서 개념적으로, 프로세스가 생성될 때, 상호작용을 위한 장치는 운영체제가 이미 활성화된 상태로 가지고 있기 때문에, 이를 프로세스에 그대로 전달하는 형태가 됩니다.(이 때, 프로세스에서 외부 장치에 입출력하기 위한 방법으로 유닉스는 파일 디스크립터로 일관되게 다룹니다.) 그래서 프로세스가 생성될 때, 이미 활성화되어 있는 장치를 표준입력,표준출력,표준에러출력순으로 파일 디스크립터를 할당하여, 0,1,2이 되었습니다.
    • 간단하게 생각하면, 쉘에서는 이미 표준입력,표준출력,표준에러출력을 열고 있는데, 프로세스가 이 장치들을 공유한다고 생각해보세요.
    • 운영체제 관점으로 설명하면 다르겠습니다(fork의 기본 개념을 이해하면 됩니다)만, 개념적으로 이해하시면 위와 같다고 생각하시면 됩니다. 만약 과거에 운영체제를 디자인한 사람이 다르게 생각했다면, 프로그램에서 기본 입출력 장치를 초기화해야만 하는 상황이 될 수도 있겠습니다만, 현대의 대부분의 운영체제는 콘솔 프로그램에서 대해서 표준입력,표준출력,표준에러출력 개념을 그대로 도입하여 사용하고 있고, 이러한 개념이 표준 C에서는, stdin, stdout, stderr과 같은 미리 정의된 FILE 구조체로 정의되어, 사용하도록 하고 있습니다.
    • 답변 감사합니다. 파일 디스크립터의 기본적인 개념에 대해서는 이해가 되는데요. "모든 프로세스는 3개의 파일 스트림을 항상 열고 있다"와 "ls라는 프로그램 코드를 실행하는 프로세스가 리눅스 커널에 만들어질 테고,"가 이해가 잘 안되네요. 죄송하지만 이 부분만 부가적으로 좀 더 쉽게 설명해주실 수 있나요 ㅠ? 알 수 없는 사용자 2016.7.11 17:31
    • 추가 답변을 적었습니다. 허대영(소프트웨어융합대학) 2016.7.11 18:42

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)