「Shell」- 进程替换(Process substitution)

什么是进程替换

先看 WIKI 的解释:

In computing, process substitution is a form of inter-process communication that allows the input or output of a command to appear as a file.

在计算中,进程替换是进程间通信的一种形式,允许命令的输入或输出作为文件出现;

进程替换的语法

cmd1 >(cmd2)

将 cmd1 输出发送给 cmd2

cmd1 <(cmd2)

将 cmd2 的输出发送给 cmd1

在这里:>(cmd2)或者<(cmd2)等价于一个内容为 cmd2 输出的文件。这么说可能不明白,请看下面“进程替换的机制”;

进程替换的机制

题外话: 如果你不会英语,你真的会错过很多东西;

进程替换的实现有两种:

  • 在支持 /dev/fd 的系统上(大多数都支持),通过 pipe()系统调用实现。pipe()系统调用会为匿名管道返回一个文件描述符$fd,然后用字符串 /dev/fd/$fd 替换命令行上的>(cmd2)或者<(cmd2);
  • 对于不支持 /dev/fd 的系统上,Bash 使用新临时文件名调用 mkfifo 来创建一个命名管道,然后使用此文件名作为替代;

为了演示所涉及的步骤,思考如下命令:

diff file1 <(sort file2)

shell 的执行步骤如下(对于支持 /dev/fd 的系统):

  • 创建一个新的匿名管道。这个管道可以通过像 /dev/fd/63 这样的东西访问;你可以用echo <(true)命令看到它;
  • 在后台执行替代命令(当前为 sort file2),将输出输送到匿名管道;
  • 执行主命令,使用匿名管道的路径替换替带命令。在这个例子中,完整的命令可能扩展为:diff file1 /dev/fd/63
  • 当执行结束时,关闭匿名管道;

对于命名管道(不支持 /dev/fd 的系统),唯一不同的地方在于管道的创建和删除:使用 mkfifo 创建;使用 unlink 删除。其他方面一样的;

进程替换的示例

#!/bin/sh

echo <(ls)

# 输出:
# /dev/fd/63

对于cmd1 >(cmd2),当 Bash 在执行进程替换的时候,Bash 会将 cmd2 的标准输出

参考文献

http://teliute.org/linux/abs-3.9.1/process-sub.html
https://en.wikipedia.org/wiki/Process_substitution