【发布时间】:2016-07-15 18:40:18
【问题描述】:
command1 | command2 和 command2 <(command1) 有区别吗?
例如,git diff | more 与 more <(git diff)
我的理解是两者都采用command2 的标准输出并将其通过管道传输到command1 的标准输入。
【问题讨论】:
command1 | command2 和 command2 <(command1) 有区别吗?
例如,git diff | more 与 more <(git diff)
我的理解是两者都采用command2 的标准输出并将其通过管道传输到command1 的标准输入。
【问题讨论】:
主要区别在于<(...),称为“进程替换”,由shell 转换为作为常规参数传递给命令的文件名;它不会向命令的标准输入发送任何内容。这意味着它不能直接与诸如 tr 之类的不带文件名参数的命令一起使用:
$ tr a-z A-Z <(echo hello)
usage: tr [-Ccsu] string1 string2
tr [-Ccu] -d string1
tr [-Ccu] -s string1
tr [-Ccu] -ds string1 string2
但是,您始终可以在 <(...) 前面放置另一个 < 以将其转换为输入重定向:
$ tr a-z A-Z < <(echo hello)
HELLO
而且因为它会生成一个文件名,所以您可以使用带有多个文件参数的命令进行进程替换:
$ diff -u <(echo $'foo\nbar\nbaz') <(echo $'foo\nbaz\nzoo')
--- /dev/fd/63 2016-07-15 14:48:52.000000000 -0400
+++ /dev/fd/62 2016-07-15 14:48:52.000000000 -0400
@@ -1,3 +1,3 @@
foo
-bar
baz
+zoo
另一个显着的区别是管道创建的子壳在父环境中不会产生副作用:
$ echo hello | read x
$ echo $x
# nothing - x is not set
但是使用进程替换,只有括号内的进程在子shell中;周围的命令仍然会产生副作用:
$ read x < <(echo hello)
$ echo $x
hello
值得一提的是,您也可以使用>(...) 写入进程,尽管这样有用的情况较少:
$ echo hello > >(cat)
hello
【讨论】:
a | b 从可执行文件 a 获取 stdout 输出并将其作为 b 的 stdin 提供给可执行文件 b。
a > b 从可执行文件a 中获取stdout,并将其重定向/写入文件b。
a < b 获取文件b 的内容并将其重定向/输入到可执行文件a 作为其stdin
换句话说,| 管道输出在程序之间,而< 和> 管道文件进入/退出程序。
您的带有() 的版本运行一个额外的过程,同时完成基本相同的事情。
【讨论】:
<(…) 符号与您描述的不同!它生成一个文件名;要从中重定向,您需要 < <(…) — 或 > >(…) 进行输出重定向。