22

In bash, I want to assign my current working directory to a variable. Using a subshell, I can do this.

var=$(pwd) echo $var /home/user.name 

If I use process substitution like so:

var=<(pwd) echo $var /dev/fd/63 

I have understood that process substitution is primarily used when a program does not accept STDIN. It is unclear to me what a process substitution exactly does and why it assigns /dev/fd/63 to var.

2 Answers 2

29

A command substitution ($(...)) will be replaced by the output of the command, while a process substitution (<(...)) will be replaced by a filename from which the output of the command may be read. The command, in both instances, will be run in a subshell.

In your case, the output from pwd in <(pwd) may be found at /dev/fd/63. This file ceases to exist as soon as the command that uses the process substitution has finished executing (when the assignment to var in your example is done).

The filename returned by a process substitution is the name of a file descriptor or named pipe, not a regular file:

Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files.

A common use of process substitution is to pre-sort files for the join command:

$ join <( sort file1 ) <( sort file2 ) 

or for removing columns from a file (here, column 2 is removed from a tab-delimited file by using cut twice and paste to stitch the result together):

$ paste <( cut -f 1 file ) <( cut -f 3- file ) 

Process substitution is more or less a syntactical shortcut for avoiding using temporary files explicitly.


Both command substitutions and process substitutions are performed in subshells. The following shows that the environment in these subshells do not affect the parent shell's environment:

$ unset t $ echo "$( t=1234; echo "$t" )" 1234 $ echo "$t" (empty line output) 

Here, echo gets 1234 as a string argument from the command substitution.

$ unset t $ cat <( t=4321; echo "$t" ) 4321 $ echo "$t" (empty line output) 

Here, cat get the filename of a file (named pipe/file descriptor) as its argument. The file contains the data 4321.

3
  • Is there a way to "open" / look inside /dev/fd/63 somehow to directly see "what's inside" ? I could not yet make good sense of this Q&A on that matter, but it might have some valid points. Commented Feb 22, 2023 at 13:03
  • @nuttyaboutnatty To any process opening and reading what's on that path, it would be equivalent to reading from a pipe, i.e., you would be able to read the data (which would be the output of the command in the process substitution), but you can't seek backwards or forwards in the stream. It's a bit unclear what you mean by "open/look inside". Commented Feb 22, 2023 at 13:17
  • I'm just trying to get my head around, and my hands dirty with askubuntu.com/a/1456103/16023; of all the stuff I'm looking into, this stackoverflow.com/a/2444163/2153622 helps. Commented Feb 22, 2023 at 14:32
2

Another important difference between command substitution and process substitution is that the former will not output anything until the command is completely executed, but the latter will immediately print out the resulting lines when they're produced.

The following experiment shows this:

$ time head -n1 <(seq 1 1000000) 1 real 0m0.003s user 0m0.002s sys 0m0.001s $ time head -n1 <<< "$(seq 1 1000000)" 1 real 0m0.546s user 0m0.433s sys 0m0.107s 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.