dup2 / dup-파일 설명자를 복제해야하는 이유는 무엇입니까?


85

dup2및 의 사용을 이해하려고합니다 dup.

man 페이지에서 :

DESCRIPTION

dup and dup2 create a copy of the file descriptor oldfd.
After successful return of dup or dup2, the old and new descriptors may
be used interchangeably. They share locks, file position pointers and
flags; for example, if the file position is modified by using lseek on
one of the descriptors, the position is also changed for the other.

The two descriptors do not share the close-on-exec flag, however.

dup uses the lowest-numbered unused descriptor for the new descriptor.

dup2 makes newfd be the copy of oldfd, closing newfd first if necessary.  

RETURN VALUE

dup and dup2 return the new descriptor, or -1 if an error occurred 
(in which case, errno is set appropriately).  

시스템 호출이 필요한 이유는 무엇입니까? 파일 설명자를 복제하는 용도는 무엇입니까?

파일 설명자가있는 경우 복사본을 만드는 이유는 무엇입니까?

dup2/ dup가 필요한 곳을 설명하고 예를 들어 주시면 감사하겠습니다 .

감사


dup또는 없이 쉘의 배관 기능을 어떻게 구현 dup2하시겠습니까? 당신은 호출 할 필요가 pipe(2)파일 기술자 중 하나를 가지고 다음과 dup예에 -edSTDIN_FILENO
실레 Starynkevitch

답변:


46

dup 시스템 호출은 기존 파일 설명자를 복제하여 동일한 기본 I / O 개체를 참조하는 새 설명자를 반환합니다.

Dup을 사용하면 쉘이 다음과 같은 명령을 구현할 수 있습니다.

ls existing-file non-existing-file > tmp1  2>&1

2> & 1은 디스크립터 1의 중복 인 파일 디스크립터 2를 명령에 제공하도록 쉘에 지시합니다 (즉, stderr & stdout가 동일한 fd를 가리킴).
이제 존재하지 않는 파일 에서 ls 를 호출하는 오류 메시지 와 ls 의 올바른 출력파일 기존 에 쇼를 tmp1의 파일을.

다음 예제 코드는 파이프의 읽기 끝에 연결된 표준 입력으로 wc 프로그램을 실행합니다.

int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {
    close(STDIN); //CHILD CLOSING stdin
    dup(p[STDIN]); // copies the fd of read end of pipe into its fd i.e 0 (STDIN)
    close(p[STDIN]);
    close(p[STDOUT]);
    exec("/bin/wc", argv);
} else {
    write(p[STDOUT], "hello world\n", 12);
    close(p[STDIN]);
    close(p[STDOUT]);
}

자식은 읽기 끝을 파일 설명자 0에 복제하고, p의 파일 디스크립터를 닫고, wc를 실행합니다. wc가 표준 입력에서 읽을 때 파이프에서 읽습니다.
이것이 dup을 사용하여 파이프를 구현하는 방법입니다. 이제 dup을 사용하여 파이프를 사용하여 다른 것을 빌드합니다. 시스템 호출의 아름다움입니다. 이미있는 도구를 사용하여 하나씩 차례로 빌드합니다.이 도구는 다음을 사용하여 빌드되었습니다. 다른 것 등등 .. 마지막에 시스템 호출은 커널에서 얻을 수있는 가장 기본적인 도구입니다.

건배 :)


1
그래서 프로그램 자체가 dup아니라 호출자에게 도움이 ls됩니까? dup이미 파일에 대한 액세스 권한이있는 경우 ls와 같은 프로그램에서 사용 하면 어떤 이점이 있습니까? 예를 들어 여기에 하드 코딩 된 ls오류를 작성 2하므로 ls. 미묘한 점이 아니라고 생각합니다.
Nishant

2
예제 프로그램 에 버그가있는 것 같습니다 . 당신은 전화 dup(p[STDIN])했지만 결과를 버립니다. 사용하려고 했습니까 dup2(p[STDIN], 0)?
Quuxplusone 2017-08-08

1
@Quuxplusone dup은 "현재 프로세스에서 사용하지 않는 가장 낮은 번호의 설명자"를 반환합니다. fd 0이 막 닫 혔기 때문에 0을 dup반환 dup2해야합니다. 가장 낮은 자유 fd를 사용하는 대신 어떤 fd를 사용해야하는지 명시 적이므로 선호합니다.
Wodin

@Wodin : 아, OP가 무슨 생각을했는지에 대해 당신이 옳다고 확신합니다. "방금 닫힘"이 상대적이고 예를 들어 파일을 여는 동시 스레드가있는 경우 OP의 코드가 손상 될 수 있다는 것도 맞습니까?
Quuxplusone 2017

@Quuxplusone 나는 당신이 옳다고 생각하지만 확실하지 않습니다. 그러나이 경우 다른 문제가 발생합니다. 다른 곳에서 읽고 싶어서 stdin을 닫은 다음 다른 스레드가 파일을 먼저 열면 fd 0이됩니다. 그런 다음 dup2를 사용하면 다른 스레드가 열린 fd를 닫습니다. 따라서 다른 스레드는 이제 열어 본 파일을 읽고 쓸 수 있습니까? 어쨌든, 내가 올바르게 기억한다면 exec*다중 스레드 프로세스에서 호출해서는 안됩니다 . 그러나 나는 더 : 전문가를 스레딩하지 오전
Wodin

18

파일 설명자를 복제하는 또 다른 이유는 fdopen. fclose에 전달 된 파일 설명자를 닫습니다. fdopen따라서 원래 파일 설명자가 닫히지 않도록하려면 dup먼저 복제해야합니다 .


fdopen()파일 설명자를 복제하지 않고 사용자 공간에 버퍼를 만듭니다.
에릭 왕

3
당신은 내 대답을 잘못 읽었습니다. 요점은 당신이 할 수 있다는 것입니다 dup에 전달하기 전에 FD fdopen이후 fclose를 닫습니다.
R .. GitHub STOP HELPING ICE

1
@ theferrit32 : FILEstdio 인터페이스를 통해 기존 열린 파일에 액세스 하기 위해 핸들을 할당하는 경우 fclose해당 FILE핸들 을 할당 해제 하기 위해 호출해야합니다 . 당신이 기본 열려있는 파일을 사용하거나 유지하려면 소프트웨어 아키텍처는 파일 기술자의 원래 "소유자"코드는 것 같은 경우 close는, 사실 fclose또한 물려 기본 파일 기술자를 닫가 fdopen문제입니다. 당신은 사용하여이 문제를 방지 할 수 있습니다 dup에 전달하기 위해 동일한 열린 파일에 새 파일 기술자를 만들기 위해 fdopen즉, 그래서 fclose가까운 원래 하나를하지 않습니다.
R .. GitHub STOP HELPING ICE

1
요점은 fdopen () fd의 소유권을 복사 하는 FILE대신으로 이동 한다는 것 입니다. 사용자가 알아야 할 사항입니다. 개체 외에 사용 가능한 핸들 을 유지해야하는 소비자 는 . 그게 다야. fdFILEfd
Conrad Meyer

1
@ConradMeyer : 예, FILE소유권을 이동 한 후에 는 "소유권을 이동"하는 작업이 없다는 점에 유의 하십시오.
R .. GitHub STOP HELPING ICE

4

dup은 프로세스에서 출력을 리디렉션하는 데 사용됩니다.

예를 들어, 프로세스의 출력을 저장하려면 출력을 복제 (fd = 1)하고 복제 된 fd를 파일로 리디렉션 한 다음 프로세스를 분기하여 실행하고 프로세스가 완료되면 다시 리디렉션합니다. fd를 출력에 저장했습니다.


4

dup / dup2와 관련된 몇 가지 사항을 알려주십시오.

dup / dup2-기술적으로 목적은 다른 핸들 로 단일 프로세스 내에서 하나의 파일 테이블 항목을 공유하는 것입니다 . (포킹하는 경우 디스크립터는 기본적으로 자식 프로세스에서 복제되며 파일 테이블 항목도 공유됩니다).

즉, 다른 속성을 가진 둘 이상의 파일 설명자를 가질 수 있습니다. dup / dup2 함수를 사용하여 하나의 열린 파일 테이블 항목에 대해 을 있습니다.

(현재 FD_CLOEXEC 플래그 만 파일 설명자에 대한 유일한 속성 인 것처럼 보이지만).

http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html

dup(fd) is equivalent to fcntl(fd, F_DUPFD, 0);

dup2(fildes, fildes2); is equivalent to 

   close(fildes2);
   fcntl(fildes, F_DUPFD, fildes2);

차이점은 (마지막)-일부 errno 값을 제외하고는 dup2 및 fcntl close 다음에 fcntl이 두 개의 함수 호출이 관련되어 있기 때문에 경쟁 조건을 일으킬 수 있습니다.

자세한 내용은 http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html 에서 확인할 수 있습니다 .

사용 예 -

아래 링크에서 dup / dup2의 사용을 볼 수있는 쉘에서 작업 제어를 구현하는 동안 흥미로운 예가 하나 있습니다.

http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.