2

I did a silly thing today:

read x <( ps -fu $LOGNAME | grep ' /usr/bin/ps$' )

It hung, never returned. I had to break it.

Some of you are quite rightly laughing at me right now. :)

It only took me a minute to see why this doesn't work, but I wanted to post it as a question (which I will briefly answer below as well, but feel free) in case it stumped someone.

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36

1 Answers1

2

If you replace read x with cat, how long does it take to run?

The problem is that you executed a command like:

read x /dev/fd/63

(as you could see by running echo read x <(…)) and the read sat there waiting for you to type something for it to put in x.

$ read x <( ps -fu $LOGNAME | grep ' /usr/bin/ps$' )
asc def
-bash: read: `/dev/fd/63': not a valid identifier
$

The shell was waiting for you to type something, that's all. You got impatient.

If you want to redirect the input to the read commnd, you need a separate < to do that (I needed to change the grep regex to get any output):

$ read x < <( ps -fu $LOGNAME | grep ' /usr/bin/ps' )
$ echo $x
501 16166 16164 0 7:50AM ttys000 0:00.00 grep /usr/bin/ps
$

Note that with the direct redirection as shown in the last read command, only the first line of input from the process substitution will be read; the rest will be lost. If you need to process multiple lines in a while loop, you need to redirect the whole loop:

while read x
do
    whatever -with "$x"
done < <(ps -fu $LOGNAME | grep ' /usr/bin/ps')

See also the Bash manual on Process Substitution, where it says:

Process substitution allows a process’s input or output to be referred to using a filename.

The result is a file name (on a Mac at least, it takes the form /dev/fd/xx for some numeric value of xx) that can be used to reference the output from the commands in the process substitution.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278