1

I would like to get the stdout from a process into another process not using stdin, as that one is used for another purpose.

In short I want to accomplish something like that:

echo  "a" >&4
cat | grep -f /dev/fd/4

I got it running using an file as source for file descriptor 4, but that is not what I want:

# Variant 1
cat file | grep -f /dev/fd/4 4<pattern

# Variant 2
exec 4<pattern
cat | grep -f /dev/fd/4
exec 4<&-

My best try is that, but I got the following error message:

# Variant 3
cat | ( 
    echo  "a" >&4
    grep -f /dev/fd/4
) <&4 

Error message:

test.sh: line 5: 4: Bad file descriptor

What is the best way to accomplish that?

codeforester
  • 39,467
  • 16
  • 112
  • 140
doak
  • 809
  • 9
  • 24

2 Answers2

4

You don't need to use multiple streams to do this:

$ printf foo > pattern
$ printf '%s\n' foo bar | grep -f pattern
foo

If instead of a static file you want to use the output of a command as the input to -f you can use a process substitution:

$ printf '%s\n' foo bar | grep -f <(echo foo)
foo
l0b0
  • 55,365
  • 30
  • 138
  • 223
  • Ah, I got process substitution wrong: even `grep -f <(echo FOO) -i` would work for example. But isn't there any way to do it piping around. I seems to me more readable... (but perhaps that is a wrong assumption) – doak Apr 01 '17 at 21:17
  • Can you have a look to some similar question: http://stackoverflow.com/questions/19715318/ – doak Apr 02 '17 at 10:42
0

For POSIX shells that lack process substitution, (e.g. dash, ash, yash, etc.).

If the command allows string input, (grep allows it), and the input string containing search targets isn't especially large, (i.e. the string doesn't exceed the length limit for the command line), there's always command substitution:

$ printf '%s\n' foo bar baz | grep $(echo foo)
foo

Or if the input file is multi-line, separating quoted search items with '\n' works the same as grep OR \|:

$ printf '%s\n' foo bar baz | grep "$(printf "%s\n" foo bar)"
foo
bar
Community
  • 1
  • 1
agc
  • 7,973
  • 2
  • 29
  • 50
  • The input is large and has serveral lines (several patterns for `grep`). @l0b0 solution matches better. – doak Apr 02 '17 at 10:38
  • @doak, Re "*several lines*": that doesn't sound that large. For the *multi-line* version of the above code to fail, the byte length of the whole list of target strings would need to be (almost) greater than the output of `getconf ARG_MAX`, (*e.g.* on my current system that's *2097152*). – agc Apr 02 '17 at 15:03
  • 1
    It is a good alternative without process substituion. Nevertheless I don't like the additional `sed` in the multi-line version. – doak Apr 05 '17 at 21:42
  • @doak, Thanks! Your comment lead to the discovery that the `sed` portion was unnecessary, it seems that newlines in a quoted string mean *OR* to `grep` -- or at least to *GNU* `grep`. – agc Apr 05 '17 at 22:25