unix系统的重定向

17 阅读2分钟

请描述命令 ls -l | grep ".txt"在执行时,Shell是如何为 lsgrep两个进程设置文件描述符的?特别是,管道两端的进程如何做到一个写、一个读?

答案与解释:

  1. 创建管道:Shell首先调用 pipe(int pipefd[2])系统调用。这个调用创建一条内核缓冲区管道,并返回两个文件描述符:pipefd[0](读端)和 pipefd[1](写端)。
  2. ls进程设置输出:Shell fork()出第一个子进程(ls),在这个子进程中,调用 dup2(pipefd[1], STDOUT_FILENO),将 ls的标准输出(1)重定向到管道的写端。然后关闭 pipefd[0]pipefd[1](原始的),最后 exec("ls", "-l", NULL)
  3. grep进程设置输入:Shell再次 fork()出第二个子进程(grep),在这个子进程中,调用 dup2(pipefd[0], STDIN_FILENO),将 grep的标准输入(0)重定向到管道的读端。然后关闭 pipefd[0]pipefd[1],最后 exec("grep", ".txt", NULL)
  4. Shell父进程:关闭它自己持有的 pipefd[0]pipefd[1]
  5. 协作:当 ls开始运行时,它向文件描述符1(它以为是屏幕)写入数据,实际上数据被送入内核的管道缓冲区。当 grep开始运行时,它从文件描述符0(它以为是键盘)读取数据,实际上是从同一个管道缓冲区读取 ls写入的数据。操作系统内核的管道缓冲区自动处理了进程间的同步和通信,如果缓冲区满,lswrite会被阻塞;如果缓冲区空,grepread会被阻塞。

这个机制完美体现了Unix的模块化思想:lsgrep这两个完全独立、对彼此一无所知的程序,通过Shell和操作系统提供的重定向/管道机制,无缝地串联起来,完成了一个更复杂的任务。

总结

重定向是操作系统赋予Shell的强大能力,它通过对进程文件描述符表的“幕后操作”,实现了程序I/O源的灵活切换。这种设计让简单的程序(如你的I/O复制器)具备了惊人的通用性,也让命令行界面成为一个极其高效和强大的编程环境。理解重定向,是理解Unix/Linux系统设计和Shell编程精髓的关键一步。