Is there a difference between command1 | command2
and command2 <(command1)
?
For example, git diff | more
vs more <(git diff)
My understanding is that both take the stdout of command2
and pipe it to the stdin of command1
.
The main difference is that <(
...)
, called "process substitution", is translated by the shell into a filename that is passed as a regular argument to the command; it doesn't send anything to the command's standard input. This means that it can't be used directly with commands such as tr
which don't take a filename argument:
$ 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
However, you can always put another <
in front of the <(
...)
to turn it into an input redirection instead:
$ tr a-z A-Z < <(echo hello)
HELLO
And because it generates a filename, you can use process substitution with commands that take more than one file argument:
$ 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
The other significant difference is that a pipe creates subshells which can't have side effects in the parent environment:
$ echo hello | read x
$ echo $x
# nothing - x is not set
But with process substitution, only the process inside the parentheses is in a subshell; the surrounding command can still have side effects:
$ read x < <(echo hello)
$ echo $x
hello
Worth mentioning that you can also write into a process with >(
...)
, although there are fewer cases where that's useful:
$ echo hello > >(cat)
hello
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With