6

This is my loop program, running in the background and waiting for a command.

#include <iostream>

using namespace std;

char buffer[256];

int main(int argc, char *argv[])
{
    while(true){
     fgets(buffer, 255, stdin);
     buffer[255] = 0;
     if(buffer[0] != '\0'){
        cout << buffer;
        buffer[0] = '\0';
     } 
    }
 return 0;
}

I ran it with:

myLoop &

Now, how can I pipe a command to this process?

  • 5
    You don't. If you actually run the program the way you say you did you'll note the shell saying something like [1]+ Stopped. That's because your program has received a SIGTTIN signal, for trying to read from the terminal while running in background. – Satō Katsura Aug 5 '17 at 16:37
14

I guess that is impossible with a "real" pipeline.

Instead you can use a FIFO (named pipe, see man mkfifo) or (more elegant but more complicated) a Unix socket (AF_UNIX).

./background-proc </path/to/fifo &
cat >/path/to/fifo
# typing commands into cat

I am not a developer so my only relation to sockets is socat. But that may help as a start.

You need a "server" which communicates with your program. Such a pipeline would be started in the background:

socat UNIX-LISTEN:/tmp/sockettest,fork STDOUT | sed 's/./&_/g'

The sed is just for testing.

Then you start one or more

socat STDIN UNIX-CONNECT:/tmp/sockettest

If you have a program which generates the commands for your background program then you would use a pipeline here, too:

cmd_prog | socat STDIN UNIX-CONNECT:/tmp/sockettest

The advantage in comparison with a FIFO is that (with the option fork on the server side) you can disconnect and reconnect the client. Using a FIFO you would need tricks for keeping the receiving side running:

while true; do cat /path/to/fifo; done | background_prog
  • Thank you, i think the best way is fifo. can you refer me to a good example of Unix socket (AF_UNIX)? – mamrezo Aug 5 '17 at 17:36
  • @mamrezo see edit – Hauke Laging Aug 5 '17 at 23:15
4

Generally, you can't change what files a process has open and where they point to from outside that process after the process has been started. There are exceptions in the form of debugging interfaces and tools like repty that can do this in a limited fashion.

When you started your program with

myLoop &

its standard input was connected to your terminal (because you didn't redirect it anywhere else) and that's not going to change to a pipe.

See also How to attach terminal to detached process?

3

If you wanted to start the command in background and have a file descriptor to send data to it via a pipe.

With zsh or bash, you could use a redirection to a process substitution.

exec 3> >(cmd)

And then send output with:

echo something >&3

And tell end-of-file with exec 3>&-.

Sill with zsh and bash, you can also do:

{ coproc cmd >&3 3>&-; } >&3

That is start cmd as a co-process, which starts the process with two pipes, one for input, one for output, but here as we only want the one for input, we restore cmd's stdout to that of the rest of the shell.

To send output:

echo something >&p # with zsh
echo something >&"${COPROC[1]}" # with bash

With yash, you can use process redirection:

exec 3>(cmd)

With any Bourne-like shell, you can always do:

{ {
  echo something >&3
  echo whatever
  ...
} 3>&1 >&4 4>&- | cmd; } 4>&1

That's not exactly the same as starting cmd in background and run commands that send their output to cmd in that those commands run in a subshell and, for interactive shells, cmd is also in the foreground (is affected by Ctrl+C for instance), but apart from that, it's mostly functionally equivalent.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.