How to send reads and writes on a single file descriptor to different places

file-descriptorsio-redirection

I have a Linux executable foo that reads input from fd 0 and writes output to fd 0 (not fd 1). This works just fine for interactive use in the terminal.

From the shell command line, how can I execute this program such that reads from fd 0 come from one file, but writes to fd 0 go into a different file?

The best I can come up with is $ goo input.txt output.txt | foo where goo is some helper program, but I don't know of any existing helper program, and I don't even know if the pipe set up by | is bidirectional.

Best Answer

With socat (version 2 or above):

socat 'system:cat input.txt & cat > output.txt,commtype=socketpair' \
      'system:foo,nofork'

Or even better:

socat 'CREATE:output.txt%OPEN:input.txt' 'system:foo,commtype=socketpair'

We're using a socketpair which is bidirectional (pipes are not bidirectional on Linux). Another option is to use a pseudo-terminal (bidirectional as well) by using commtype=pty above. That may be a better way if foo expects to talk to a terminal.

Or you implement the socketpair approach in perl like:

perl -MSocket -e '
  socketpair(A, B, AF_UNIX, SOCK_STREAM, PF_UNSPEC);
  if (fork) {
    close A;
    if (fork) {
      open STDOUT, ">&B";
      exec("cat", "input.txt")
    }
    open STDIN, "<&B";
    open STDOUT, ">output.txt";
    exec("cat")
  }
  close B;
  open STDIN, "<&A";
  exec "foo"'

(here as a quick proof-of-concept, you may want to add error checking and make it more efficient by not using that many processes and avoid executing cat).

Related Question