Shell如何以编程方式实现管道



我了解I/O重定向在Unix/Linux中是如何工作的,我知道Shell使用此功能通过一种特殊类型的文件-匿名管道来管道化程序。但我想知道Shell如何通过编程实现它的细节?我不仅对所涉及的系统调用感兴趣,而且对整个画面感兴趣。

例如ls | sort,Shell如何为lssort执行I/O重定向?

整个画面很复杂,最好的理解方法是研究一个小外壳。对于有限的图片,如下所示。在做任何事情之前,shell会解析整个命令行,以便它确切地知道如何链接进程。假设它遇到proc1|proc2。

  • 它设置了一个管道。长话短说,写入thepipe[0]最终进入thepipe[1]

    int thepipe[2];
    pipe(thepipe);
    
  • 它分叉第一个进程,并在exec之前更改其stdout的方向

    dup2 (thepipe[1], STDOUT_FILENO);
    
  • 它执行新程序,该程序很幸运地不知道重定向,只是像一个行为良好的进程一样写入stdout

  • 它分叉第二个进程,并在exec之前更改其stdin的源

    dup2 (thepipe[0], STDIN_FILENO);
    
  • 它执行新程序,它不知道它的输入来自另一个程序

就像我说的,这是一张有限的图片。在真实的照片中,外壳将这些菊花链成一个环,还记得在适当的时候关闭管道末端。

这是silberschatz 的《操作系统概念》一书中的一个示例程序

如果您知道fork()和相关事物的概念,那么程序是不言自明的。。希望这能有所帮助!(如果你还想解释,那么我可以解释!)

显然,如果你想让这个程序像一样工作,就应该在这个程序中进行一些更改(比如fork()中的更改等)

ls | sort

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#define BUFFER SIZE 25
#define READ END 0
#define WRITE END 1
int main(void)
{
char write msg[BUFFER SIZE] = "Greetings";
char read msg[BUFFER SIZE];
int fd[2];
pid t pid;
/* create the pipe */
if (pipe(fd) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
if (pid > 0) { /* parent process */
/* close the unused end of the pipe */
close(fd[READ END]);
/* write to the pipe */
write(fd[WRITE END], write msg, strlen(write msg)+1);
/* close the write end of the pipe */
close(fd[WRITE END]);
}
else { /* child process */
/* close the unused end of the pipe */
close(fd[WRITE END]);
/* read from the pipe */
read(fd[READ END], read msg, BUFFER SIZE);
printf("read %s",read msg);
}
}
/* close the write end of the pipe */
close(fd[READ END]);
return 0;
}

最新更新