打破shell脚本; 引擎盖下,会发生什么?(Breaking down shell scrip

2019-10-19 00:54发布

所以,我得到了这一行脚本:

echo test | cat | grep test

能否请您给我解释一下究竟如何,将工作给予以下系统调用:管(),叉(),exec()和DUP2()?

我找了一个概述这里主要的操作顺序。 我所知道的,到目前为止是Shell会fork使用fork()和脚本的代码将使用exec更换外壳的一个()。 但是,我们管DUP2? 他们如何在地方跌倒吗?

提前致谢。

Answer 1:

首先考虑一个简单的例子,如:

echo test | cat

我们需要的是执行echo在一个单独的进程,安排它的标准输出要改进程中执行的标准输入cat 。 理论上讲,该引水,一旦安装,就需要由shell没有进一步的干预 - 壳只想平静地等待两个进程退出。

实现这一机制被称为“管道”。 它是在内核中实现,并出口到用户空间进程间通信装置。 一旦通过一个Unix程序创建,管有一对文件描述符用,如果你写入其中之一,你可以阅读从其他的相同数据的特殊属性的外观。 这不是在同一进程中非常有用,但要记住,文件描述符,包括但不限于管道,跨继承fork() ,甚至翻过exec() 这使得管道易于设置和合理有效的IPC机制。

外壳创建管道,现已拥有一套属于管道,一个用于读取,一个用于写入文件描述符。 这些文件描述符被两个分叉子进程继承。 现在,只有当echo被写入管道的写入终止描述符,而不是其实际的标准输出,如果cat被从管道的读取结束描述,而不是从标准输入读取,就不会有什么问题。 但他们不这样做,而这正是dup2的用武之地。

dup2复制文件描述符作为另一文件描述符,预先自动关闭所述新的描述符。 例如, dup2(1, 15)将关闭文件描述符1(通过用于标准输出约定),然后重新打开它作为文件描述符15的副本-意味着写入到标准输出将实际上等同于写文件描述符15.这同样适用于阅读: dup2(0, 8)将使从文件描述符0(标准输入)等效读取从文件描述符8.读取如果我们着手关闭原始文件描述符,打开文件(或管道)将已有效地从原来的描述符到新移动,很像科幻瞬间移动通过在远程位置的第一复制一件事情,然后崩解原来的工作。

如果你还在下面的理论,操作由shell执行的顺序现在应该清楚:

  1. 壳创建一个管道,然后fork两个过程,这两者将继承管文件描述符, rw

  2. 在将要执行的子过程echo ,所述壳调用dup2(1, w); close(w) dup2(1, w); close(w)exec以重定向标准输出到管道的写入结束。

  3. 在将要执行的子过程cat ,壳调用dup2(0, r); close(r) dup2(0, r); close(r)以标准输入重定向到管道的读端。

  4. 分叉后,主壳过程本身必须关闭管道的两端。 原因之一是释放与管道一旦子过程的出口相关联的资源。 另一种是让cat来实际终止-管道的读者将获得EOF管道写端的所有副本都关闭之后。 在上面的步骤,我们也关闭了孩子的冗余写入结束的拷贝,文件描述符15,其复制到1。但文件描述符15还必须存在于父之后,因为它是根据这个数字继承,并能仅由父被关闭。 如果不这样做,离开cat的标准输入从未报告EOF,它的cat过程中垂下的结果。

这种机制被轻松地将其推广到由管道连接的三个或多个过程。 在三道工序的情况下,管道需要安排该echo的输出写入到cat的输入,以及cat的输出写入到grep的输入。 这需要两次调用pipe()三次调用fork() ,四调用dup2()close (一个用于echogrep ,两个用于cat ),三次调用exec()以及四个额外调用close() (两个用于每个管道)。



文章来源: Breaking down shell scripts; What happens under the hood?