Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redirecting stdin _and_ stdout to a pipe

I would like to run a program "A", have its output go to the input to another program "B", as well as stdin going to intput of "B". If program "A" closes, I'd like "B" to continue running.

I can redirect A output to B input easily:
./a | ./b

And I can combine stderr into the output if I'd like:
./a 2>&1 | ./b

But I can't figure out how to combine stdin into the output. My guess would be:
./a 0>&1 | ./b
but it doesn't work.

Here's a test that doesn't require us to rewrite up any test programs:

$ echo ls 0>&1 | /bin/sh -i
$ a  b  info.txt
$
/bin/sh: Cannot set tty process group (No such process)

If possible, I'd like to do this using only bash redirection on the command line (I don't want to write a C program to fork off child processes and do anything complicated everytime I want to do some redirection of stdin to a pipe).

like image 876
markie Avatar asked Sep 13 '25 09:09

markie


2 Answers

This cannot be done without writing an auxiliary program.

In general, stdin could be a read-only file descriptor (heck, it might refer to read-only file). So you cannot "insert" anything into it.

You will need to write a "helper" program that monitors two file descriptors (say, 0 and 3) in order to read from both and "merge" them. A simple select or poll loop would be sufficient, and you could write it in most scripting languages, but not the shell, I don't think.

Then you can use shell redirection to feed your program's output to descriptor 3 of the "helper".

Since what you want is basically the opposite of "tee", I might call it "eet"...

[edit]

If only you could launch "cat" in the background...

But that will fail because background processes with a controlling terminal cannot read from stdin. So if you could just detach "cat" from its controlling terminal and run it in the background...

On Linux, "setsid cat" should do it, roughly. But (a) I could not get it to work very well and (b) I really do not have time for this today and (c) it is non-standard anyway.

I would just write the helper program.

[edit 2]

OK, this seems to work:

{ seq 5 ; sleep 2 ; seq 5 ; } | /bin/bash -c 'set -m ; setsid cat ; echo HELLO'

The set -m thing forces bash to enable job control, which apparently is needed to prevent the shell from redirecting stdin from /dev/null.

Here, the echo HELLO represents your "program A". The seq commands (with the sleep in the middle) are just to provide some input. And yes, you can pipe this whole thing to process B.

About as ugly and non-portable a solution as you could ask for...

like image 94
Nemo Avatar answered Sep 14 '25 22:09

Nemo


A pipe has two ends. One is for writing, and that which gets written appears in the other end, which is for reading.

It's a pipe, not a T or Y junction.

I don't think your scenario is possible. Having "stdin going to input of" anything doesn't make sense.

like image 20
unwind Avatar answered Sep 15 '25 00:09

unwind