Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I was wondering how to understand the following:

Piping the stdout of a command into the stdin of another is a powerful technique. But, what if you need to pipe the stdout of multiple commands? This is where process substitution comes in.

In other words, can process substitution do whatever pipe can do?

What can process substitution do, but pipe cannot?

share|improve this question
add comment

4 Answers

up vote 22 down vote accepted

A good way to grok the difference between them is to do a little experimenting on the command line. In spite of the visual similarity in use of the < character, it does something very different than a redirect or pipe.

Let's use the date command for testing.

$ date | cat
Thu Jul 21 12:39:18 EEST 2011

This is a pointless example but it shows that cat acceptedthe output ofdate` on STDIN and spit it back out. The same results can be achieved by process substitution:

$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011

However what just happened behind the scenes was different. Instead of being given a STDIN stream, cat was actually passed the name of a file that it needed to go open and read. You can see this step by using echo instead of cat.

$ echo <(date)
/proc/self/fd/11

When cat was passed the file name it read it's contents for us, but echo just showed us the name that it was passed. This difference becomes more obvious if you add more substitutions:

$ 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

It is possible to combine process substitution (which generates a file) and input redirection (which connects a file to STDIN):

$ cat < <(date)
Thu Jul 21 12:46:22 EEST 2011

It looks pretty much the same but this time cat was passed STDIN stream instead of a file name. You can see this by trying it with echo:

$ echo < <(date)
<blank>

Since echo doesn't read STDIN and no argument was passed, we get nothing.

Pipes and input redirects shove content onto the STDIN stream. Process substitution runs the commands, saves their output to a special temporary file and then passes that file name in place of the command. Whatever command you are using treats it as a file name.

share|improve this answer
add comment

Here are three things you can do with process substitution that are impossible otherwise.

Multiple process inputs

diff <(cd /foo/bar/; ls) <(cd /foo/baz; ls)

There simply is no way to do this with pipes.

Preserving STDIN

Say you have the following:

curl -o - http://example.com/script.sh
   #/bin/bash
   read LINE
   echo "You said ${LINE}!"

And you want to run it directly. The following fails miserably. Bash is already using STDIN to read the script, so other input is impossible.

curl -o - http://example.com/script.sh | bash 

But this way works perfectly.

bash <(curl -o - http://example.com/script.sh)

Outbound process substitution

Also note that process substitution works the other way too. So you can do something like this:

(ls /proc/*/exe >/dev/null) 2> >(sed -n \
  '/Permission denied/ s/.*\(\/proc.*\):.*/\1/p' > denied.txt )

That's a bit of a convoluted example, but it sends stdout to /dev/null, while piping stderr to a sed script to extract the names of the files for which a "Permission denied" error was displayed, and then sends THOSE results to a file.

Note that the first command and the stdout redirection is in parentheses (subshell) so that only the result of THAT commend gets sent to /dev/null and it doesn't mess with the rest of the line.

share|improve this answer
add comment

I should suppose you are talking about bash or some other advanced shell, because the posix shell do not have process substitution.

bash manual page reports:

Process Substitution
Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files. It takes the form of <(list) or >(list). The process list is run with its input or output connected to a FIFO or some file in /dev/fd. The name of this file is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list.

When available, process substitution is performed simultaneously with parameter and variable expansion, command substitution, and arithmetic expansion.

In other words, and from a practical point of view, you can use an expression like the following

<(commands)

as a file name for other commands requiring a file as a parameter. Or you can use redirection for such a file:

while read line; do something; done < <(commands)

Turning back to your question, it seems to me that process substitution and pipes have not much of similar.

If you want to pipe in sequence the output of multiple commands you can use one of the following forms:

(command1; command2) | command3
{ command1; command2; } | command3

but you can also use redirection on process substitution

command3 < <(command1; command2)

finally, if command3 accept a file parameter (in substitution od stdin)

command3 <(command1; command2)
share|improve this answer
add comment

If a command takes a list of files as arguments and processes those files as input (or output, but not commonly), each of those files can be a named pipe or /dev/fd pseudo-file provided transparently by process subsitution:

$ sort -m <(command1) <(command2) <(command3)

This will "pipe" the output of the three commands to sort, as sort can take a list of input files on the command line.

share|improve this answer
1  
IIRC the <(command) syntax is a bash-only feature. –  Philomath Jul 21 '11 at 8:23
    
@Philomath: It's in ZSH too. –  Caleb Jul 21 '11 at 9:37
    
Well, ZSH has everything... (or at-least tries to). –  Philomath Jul 21 '11 at 9:54
    
@Philomath: How is process substitution implemented in other shells? –  camh Jul 21 '11 at 12:23
2  
@Philomath <(), like many advanced shell features, was originally a ksh feature and was adopted by bash and zsh. psub is specifically a fish feature, nothing to do with POSIX. –  Gilles Jul 21 '11 at 16:23
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.