Answers:
解决它们之间差异的一个好方法是在命令行上做一些试验。尽管在<字符使用上具有视觉相似性,但它的功能与重定向或管道非常不同。
让我们使用date命令进行测试。
$ date | cat
Thu Jul 21 12:39:18 EEST 2011这是一个毫无意义的示例,但是它表明cat接受了dateSTDIN上的输出并将其吐出。通过流程替换可以达到相同的结果:
$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011但是,幕后发生的事情是不同的。cat实际上没有传递给STDIN流,而是传递了需要打开并读取的文件名。您可以使用echo代替来查看此步骤cat。
$ echo <(date)
/proc/self/fd/11cat收到文件名时,它将为我们读取文件的内容。另一方面,echo只是向我们显示了已通过文件的名称。如果添加更多替换,则这种区别变得更加明显:
$ cat <(date) <(date) <(date)
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
$ echo <(date) <(date) <(date)
/proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13可以将进程替换(生成文件)和输入重定向(将文件连接到STDIN)组合在一起:
$ cat < <(date)
Thu Jul 21 12:46:22 EEST 2011看起来几乎一样,但是这次猫是通过STDIN流而不是文件名传递的。您可以通过使用echo尝试查看:
$ echo < <(date)
<blank>由于echo不会读取STDIN且未传递任何参数,因此我们什么也没有。
管道和输入重定向将内容推送到STDIN流上。进程替换运行命令,将其输出保存到特殊的临时文件中,然后传递该文件名代替命令。无论您使用什么命令,都将其视为文件名。请注意,创建的文件不是常规文件,而是一个命名管道,一旦不再需要该管道便会自动删除。
[[ -p <(date) ]] && echo true。true当我使用bash 4.4或3.2运行它时,会产生这种情况。
                    我应该假设您正在谈论bash或其他高级shell,因为posix shell没有进程替代。
bash 手册页报告:
进程替换
在支持命名管道(FIFO)或命名打开文件的/ dev / fd方法的系统上支持进程替换。它采用<(list)或>(list)的形式。运行进程列表时,其输入或输出连接到FIFO或/ dev / fd中的某个文件。作为扩展结果,此文件的名称作为参数传递给当前命令。如果使用>(list)形式,则写入文件将为list提供输入。如果使用<(list)形式,则应读取作为参数传递的文件以获得list的输出。
如果可用,进程替换将与参数和变量扩展,命令替换和算术扩展同时执行。
换句话说,从实际的角度来看,您可以使用如下表达式
<(commands)作为其他需要文件作为参数的命令的文件名。或者,您可以对此类文件使用重定向:
while read line; do something; done < <(commands)回到您的问题,在我看来,过程替换和管道并没有太多共同之处。
如果要按顺序传递多个命令的输出,则可以使用以下形式之一:
(command1; command2) | command3
{ command1; command2; } | command3但您也可以在流程替换中使用重定向
command3 < <(command1; command2)最后,如果command3接受文件参数(代替标准输入)
command3 <(command1; command2)这是您可以用进程替换完成的三件事,否则它们是不可能的。
diff <(cd /foo/bar/; ls) <(cd /foo/baz; ls)用管道根本无法做到这一点。
说您有以下几点:
curl -o - http://example.com/script.sh
   #/bin/bash
   read LINE
   echo "You said ${LINE}!"您想直接运行它。以下失败了。Bash已经在使用STDIN来读取脚本,因此无法进行其他输入。
curl -o - http://example.com/script.sh | bash 但是这种方式非常有效。
bash <(curl -o - http://example.com/script.sh)另请注意,进程替换也可以采用其他方式。因此,您可以执行以下操作:
(ls /proc/*/exe >/dev/null) 2> >(sed -n \
  '/Permission denied/ s/.*\(\/proc.*\):.*/\1/p' > denied.txt )这是一个令人费解的示例,但是它将stdout发送到/dev/null,同时将stderr用管道传输到sed脚本以提取显示了“权限被拒绝”错误的文件的名称,然后将THOSE结果发送到文件。
请注意,第一个命令和stdout重定向位于括号(subshell)中,以便仅将THAT命令的结果发送至/dev/null该命令,并且不会与其余行混淆。
diff示例中,您可能要关心cd可能失败的情况:diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls)。
                    如果命令以文件列表作为参数并将这些文件作为输入(或输出,但不常见)进行处理,则这些文件中的每一个都可以是进程替换透明提供的命名管道或/ dev / fd伪文件:
$ sort -m <(command1) <(command2) <(command3)这将“传递”三个命令的输出进行排序,因为sort可以在命令行中获取输入文件的列表。
<()与许多高级Shell功能一样,@Philomath 最初是ksh功能,被bash和zsh所采用。psub特别是鱼功能,与POSIX无关。
                    应该注意的是,进程替换不限于form <(command),它使用的输出command作为文件。它也可以采用将>(command)文件作为输入的形式command。在@enzotib的答案中bash手册的引用中也提到了这一点。
对于date | cat上面的示例,使用表单的流程替换>(command)来达到相同效果的命令是,
date > >(cat)请注意,>之前>(cat)是必要的。echo如@Caleb的答案所示,这可以再次清楚地说明。
$ echo >(cat)
/dev/fd/63因此,如果没有多余的内容>,date >(cat)它将与date /dev/fd/63向stderr打印一条消息一样。
假设您有一个仅将文件名作为参数而不处理stdin或的程序stdout。我将使用过于简化的脚本psub.sh进行说明。的内容psub.sh是
#!/bin/bash
[ -e "$1" -a -e "$2" ] && awk '{print $1}' "$1" > "$2"基本上,它将测试其两个参数都是文件(不一定是常规文件),如果是这种情况,请使用awk 写入"$1"to 的每一行的第一个字段"$2"。然后,将到目前为止提到的所有内容组合在一起的命令是:
./psub.sh <(printf "a a\nc c\nb b") >(sort)这将打印
a
b
c相当于
printf "a a\nc c\nb b" | awk '{print $1}' | sort但以下操作无效,我们必须在此处使用流程替换,
printf "a a\nc c\nb b" | ./psub.sh | sort或其等效形式
printf "a a\nc c\nb b" | ./psub.sh /dev/stdin /dev/stdout | sort如果除了上面提到的./psub.sh内容stdin之外还读取其他内容,那么就不存在这种等效形式,在这种情况下,除了进程替换之外,我们什么都不能使用(当然,您也可以使用命名管道或临时文件,但这是另一种形式)故事)。