Process Substitution

Why does process substitution not work in a shell script?

It isn't entirely clear yet, but the chances are very high that you either have an incorrect shebang line at the top of the script:

#!/bin/sh

or you are using sh script.sh instead of bash script.sh while testing it, or you have SHELL=/bin/sh or something similar set in the environment. Your failure is on the process substitution code. When Bash is run as sh (in POSIX mode), then process substitution is not available:


  1. Process substitution is not available.

You need to write:

#!/bin/bash

temp=$(comm -12 <(sort -u /home/xyz/a.csv1) <(sort -u /home/abc/tempfile) | wc -l)
echo $temp

or even simply:

#!/bin/bash

comm -12 <(sort -u /home/xyz/a.csv1) <(sort -u /home/abc/tempfile) | wc -l

which will achieve the same effect as the capture followed by the echo. When testing, use bash -x script.sh or bash script.sh.


Deciphering the indecipherable comment

In an indecipherable comment, the information appears to include:

BASH=/bin/sh

BASHOPTS=cmdhist:extquote:force_fignore:hostcomplete:interactive_comments:progco‌mp:promptvars:sourcepath

BASH_ALIASES=()

BASH_ARGC=()

BASH_ARGV=()

BASH_CMDS=()

BASH_LINENO=([0]="0")

BASH_SOURCE=([0]="a.sh")

BASH_VERSINFO=([0]="4" [1]="1" [2]="2" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")

BASH_VERSION='4.1.2(1)-release'

CVS_RSH=ssh

SHELL=/bin/bash

SHELLOPTS=braceexpand:hashall:interactive-comments:posix

SHLVL=2

Note that BASH=/bin/sh and SHELLOPTS=braceexpand:hashall:interactive-comments:posix. Either or both of these might be a major part of the problem.

Idiomatic use of process substitution

Redirect into the loop's stdin with the operator <.

while read city county state; do
echo "$city lies in $county County, $state."
done < <(echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n")

Output:

Cincinnati lies in Hamilton County, Ohio.
Atlanta lies in Fulton County, Georgia.

Note that in this example, a pipe works just as well.

echo -ne "Cincinnati Hamilton Ohio\nAtlanta Fulton Georgia\n" |
while read city county state
do
echo "$city lies in $county County, $state."
done

Also, uppercase variable names should be reserved for environment variables (like PATH) and other special variables (like RANDOM). And descriptive variable names are always good.

What is the difference between using process substitution vs. a pipe?

There's no benefit here, as the line could equally well have been written like this:

wget -O - http://example.com/dvd.iso | tee dvd.iso | sha1sum > dvd.sha1

The differences start to appear when you need to pipe to/from multiple programs, because these can't be expressed purely with |. Feel free to try:

# Calculate 2+ checksums while also writing the file
wget -O - http://example.com/dvd.iso | tee >(sha1sum > dvd.sha1) >(md5sum > dvd.md5) > dvd.iso

# Accept input from two 'sort' processes at the same time
comm -12 <(sort file1) <(sort file2)

They're also useful in certain cases where you for any reason can't or don't want to use pipelines:

# Start logging all error messages to file as well as disk
# Pipes don't work because bash doesn't support it in this context
exec 2> >(tee log.txt)
ls doesntexist

# Sum a column of numbers
# Pipes don't work because they create a subshell
sum=0
while IFS= read -r num; do (( sum+=num )); done < <(curl http://example.com/list.txt)
echo "$sum"

# apt-get something with a generated config file
# Pipes don't work because we want stdin available for user input
apt-get install -c <(sed -e "s/%USER%/$USER/g" template.conf) mysql-server

Bash Process Substitution with WSL

Most likely ipconfig.exe is reading from stdin, so it's sucking up the input from the process substitution. Redirect its input to /dev/null to prevent this.

while read i;
do
((var++))
ipconfig.exe </dev/null
done < <(find dir -type d)

Bash Multiple Process Substitution Redirect Order

You can split send the error stream from the command into a different pipeline than the output, if that is desired:

{ { cmd 2>&3 | ts ... | split; } 3>&1 >&4 | ts ... | split; } 4>&1

This sends the output of cmd to the first pipeline, while the error stream from cmd goes into the 2nd pipe. File descriptor 3 is introduced to keep the error streams from ts and split separate, but that may be undesirable. fd 4 is introduced to prevent the output of split from being consumed by the second pipeline, and that may be unnecessary (if split does not produce any output, for example.)

process substitution not working in bash script

Process substitution does not work when bash is in POSIX mode. Please disable POSIX and try again.

To disable: This will cause process substitution to work .

set +o posix

To enable: : This will cause process substitution not to work.

set -o posix


Related Topics



Leave a reply



Submit