Bash – How to combine Bash’s process substitution with HERE-document

bashhere-documentprocess-substitution

In Bash version 4.2.47(1)-release when I try to catenate formatted text that comes from a HERE-dcoument like so:

cat <(fmt --width=10 <<FOOBAR
(I want the surrounding parentheses to be part of the HERE-document)
(Even the preceding unbalanced parenthesis should be part of it.
FOOBAR
) # I want this paranthesis to end the process substitution.

I get the following error:

bash: bad substitution: no closing `)' in <(fmt --width=10 <<FOOBAR
(I want the surrounding parentheses to be part of the HERE-document)
(Even the preceding unbalanced parenthesis should be part of it.
FOOBAR
)

Also I do not want to quote the HERE-document, i.e. write <'FOOBAR', because I still want to have variables being substituted within it.

Best Answer

The process substitution is roughly equivalent to this.

Example - mechanics of process substitution

Step #1 - make a fifo, output to it

$ mkfifo /var/tmp/fifo1
$ fmt --width=10 <<<"$(seq 10)" > /var/tmp/fifo1 &
[1] 5492

Step #2 - read the fifo

$ cat /var/tmp/fifo1
1 2 3 4
5 6 7 8
9 10
[1]+  Done                    fmt --width=10 <<< "$(seq 10)" > /var/tmp/fifo1

The use of parens within the HEREDOC also seems OK:

Example - just using a FIFO

Step #1 - output to FIFO

$ fmt --width=10 <<FOO > /var/tmp/fifo1 &
(one)
(two
FOO
[1] 10628

Step #2 - read contents of FIFO

$ cat /var/tmp/fifo1
(one)
(two

The trouble, I believe you're running into is that the process substitution, <(...), doesn't seem to care for the nesting of parens within it.

Example - process sub + HEREDOC don't work

$ cat <(fmt --width=10 <<FOO
(one)
(two
FOO
)
bash: bad substitution: no closing `)' in <(fmt --width=10 <<FOO
(one)
(two
FOO
)
$

Escaping the parens seems to appease it, a little:

Example - escaping parens

$ cat <(fmt --width=10 <<FOO                 
\(one\)
\(two
FOO
)
\(one\)
\(two

But doesn't really give you what you want. Making the parens balanced also seems to appease it:

Example - balancing parens

$ cat <(fmt --width=10 <<FOO
(one)
(two)
FOO
)
(one)
(two)

Whenever I have complex strings, such as this to contend with in Bash, I almost always will construct them first, storing them in a variable, and then use them via the variable, rather than try and craft some tricky one liner that ends up being fragile.

Example - use a variable

$ var=$(fmt --width=10 <<FOO
(one)
(two
FOO
)

Then to print it:

$ echo "$var"
(one)
(two

References

Related Question