내가 아는 한, 파이프의 한쪽 끝은 fd를 읽고 쓸 수 있고, 다른 쪽 끝도 fd를 읽고 쓸 수 있습니다. 이것이 바로 우리가 using을 사용하여 쓸 때 파이프의 같은 쪽 읽기 끝을 fd[1]
닫고 , using을 사용하여 두 번째 끝에서 읽을 때 해당 끝의 읽기 끝을 닫는 이유입니다. 내가 맞나요?fd[0]
fd[0]
fd[1]
답변1
예, 파이프라인()으로 생성된 파이프라인에는 두 개의 파일 설명자가 있습니다. fd[0]
읽기 및 fd[1]
쓰기용.
아니요, 파이프의 양쪽 끝을 닫을 필요가 없습니다. 양방향 통신에 사용할 수 있습니다.
편집: 댓글에서 이것이 어떤 것과 관련이 있는지 궁금해하셨으므로 ls | less
이에 대해서도 설명하겠습니다.
셸에는 0(stdin), 1(stdout), 2(stderr)의 세 가지 열린 파일 설명자가 있습니다. 쉘이 명령을 실행할 때 다음과 같은 작업을 수행합니다(약간 단순화했습니다:
pid = fork();
if(pid == 0) {
/* I am the child */
execve(...); /* Whatever the user asked for */
}
else {
waitpid(pid); /* Wait for child to complete */
}
파일 설명자 0, 1, 2는 하위 프로세스에 의해 상속되므로 입력/출력이 예상대로 작동합니다. 이렇게 하면 ls | less
리디렉션 시 약간 다른 일이 발생합니다.
int pipe[2];
pipe(pipe, 0);
pid1 = fork();
if(pid1 == 0) {
/* This is ls, we need to remap stdout to the pipe. We don't care about reading from the pipe */
close(pipe[0]);
close(1);
dup2(pipe[1], 1);
execve(...);
}
else {
pid2 = fork();
if(pid2 == 0) {
/* This is less, it reads from the pipe */
close(pipe[1]);
close(0);
dup2(pipe[0], 0);
execve(...);
}
else {
waitpid(pid1);
waitpid(pid2);
}
}
따라서 셸은 파이프를 생성하고 분기한 다음 실행 전에 파이프를 하위 프로세스의 stdin 또는 stdout에 다시 매핑하여 데이터가 프로세스 1에서 프로세스 2로 흐를 수 있도록 합니다. 쉘 파이프는 양방향이 아니기 때문에 파이프의 한쪽 끝만 사용하고 다른 쪽 끝을 닫습니다(파일 설명자를 표준 입력 또는 표준 출력에 복사한 후 실제로 다른 쪽 끝도 닫습니다).
답변2
요약입니다채팅 대화 데니스다른 초보자들도 쉽게 사용할 수 있도록 단순화했습니다. 실행할 때 ls | less
:
- bash 쉘은 , 및 의 상위
fd[0]
프로세스fd[1]
입니다fd[2]
. pipe()
부모에 의해 호출되면 데이터를 보관하기 위한 버퍼에 지나지 않는 파이프를 생성하고 각 끝에는 읽기용과 쓰기용 파일 설명자가 있습니다.- 하위 프로세스는 열려 있는 모든 fd 0, 1, 2와 파이프용 2개를 상속합니다. 따라서
ls
fds는 둘 다 자체 버퍼 복사본을 가지고 있지만 둘 다 fds의 동일한 파이프를 가리킵니다. 첫 번째 하위 프로세스 내에서 실행하면 이제 출력을 파이프( )의 쓰기 끝으로 다시 매핑한 다음 콘솔로 다시 매핑해야 합니다. 그래서 다시 매핑이 있을 것입니다. 상위 프로세스가 아닌 하위 프로세스에만 영향을 미칩니다. 이제 의 출력이 하위 파이프의 쓰기 끝으로 전달됩니다. 여전히 읽기 끝이고 데이터 자체를 읽는 것을 원하지 않으므로 로 끝을 닫아야 합니다. 다시 말하지만, 이는 .fd[0]
fd[1]
bash
ls
fd[1]
close(1)
dup(fd[1])
close(1)
ls
bash
ls
fd[1]
fd[0]
ls
close(fd[0])
ls
bash
less
파이프 파일 설명자를 상속하는 하위 프로세스를 생성하기 위해 다시 분기합니다 . 입력은less
버퍼에서 읽어야 하므로 더 이상 표준 입력이 아니므로 다시 매핑해야 하므로fd[0]
여기서 입력 은 쓰기 끝 을 읽고 닫 습니다 . 쓰고 읽은 데이터가 다시 쓰여지는 것을 방지하기 위해 필요합니다.fd[0]
close(0)
dup(fd[0])
fd[0]
ls
less
fd[0]
fd[1]
less
답변3
less 명령을 호출하기 전에 close
부모에서 fd[1]을 수행해야 합니다. 그렇지 않으면 명령이 입력을 무한정 기다리게 됩니다.fork()
less