5

I would like to send stdout to multiple commands, however I'm not sure how do I read from standard input within process substitution?

My attempts:

$ echo foo >(cat /dev/stdin) >(cat /dev/stdin)
foo /dev/fd/63 /dev/fd/62
$ echo foo >(cat -) >(cat -)
foo /dev/fd/63 /dev/fd/62
$ echo foo >(cat <&3) >(cat <&3) 3<&0
foo /dev/fd/63 /dev/fd/62
-bash: 3: Bad file descriptor
-bash: 3: Bad file descriptor

Alternative version of the same problem:

$ cat file | tee &>/dev/null >(cmd1 /dev/stdin) >(cmd2 /dev/stdin)

What's the right way of doing this?

asked Dec 6, 2015 at 19:21
13
  • do you mean - from a terminal? Commented Dec 6, 2015 at 19:24
  • @mikeserv Yes, from terminal/script using bash shell. The - points to stdin. Commented Dec 6, 2015 at 19:25
  • well... you kind of cant from a terminal - not like that. its to do with the process groups and what a controlling terminal will do with background process that try to read... there's an answer... just a minute. Commented Dec 6, 2015 at 19:27
  • I've seen that, but it doesn't solve the problem. The other question asking for the explanation why it doesn't work, however I'm looking for the solution which isn't provided there. Secondly it's other way round, there is <(cat), and I am looking for: >(cat -). Commented Dec 6, 2015 at 19:37
  • 2
    What's wrong with just echo foo | tee >(cat) >(cat)? Commented Dec 6, 2015 at 19:46

1 Answer 1

5

This reads from stdin:

echo foo | tee >(read line </dev/stdin; echo "internal $line")

You have to keep in mind that a process substitution acts "like" a file.
It could be used where a file is expected. The command tee expects to write to a file.
In that command we are being specific about the device to read from with: /dev/stdin. In that simple example, the /dev/stdin could be removed and that will work also:

echo foo | tee >(read line; echo "internal $line")

If I am understanding your need correctly, this will work:

$ echo foo | tee >(read a </dev/stdin; echo "a is $a") \
>(read b </dev/stdin; echo "b is $b") \
>(read c </dev/stdin; echo "c is $c")
foo
a is foo
c is foo
b is foo

I omitted the PS2 prompt to reduce confusion. Note that each Process Substitution replaces the use of a file (as: tee FILE FILE ....).

The read does not have to be the first command.

$ echo foo > >(echo "hello" | read b; read a </dev/stdin; echo "a is $a") 
a is foo

Note that here the "Process Substitution" needs a redirection,
that is the reason of the two > >( idiom.

A simple echo, will only print the number of the fd used (the name of the file):

$ echo >(echo "hello")
/dev/fd/63
hello

It is similar to:

$ echo "$file"
filename

Whereas this is a very different idiom:

$ echo > "$file"
answered Dec 6, 2015 at 22:09
0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.