18

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.

PejoPhylo
  • 345
  • 3
  • 6

1 Answers1

26

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.

Kusalananda
  • 333,661
  • 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. – nutty about natty Feb 22 '23 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". – Kusalananda Feb 22 '23 at 13:17
  • I'm just trying to get my head around, and my hands dirty with https://askubuntu.com/a/1456103/16023; of all the stuff I'm looking into, this https://stackoverflow.com/a/2444163/2153622 helps. – nutty about natty Feb 22 '23 at 14:32