2

In a posix shell I would like to pass data to a background child process file descriptor and process output from the child in the parent.

No mkfifo please, just standard posix shell file descriptor duplication. No non-posix features like process substitions (<(cmd)). No intermediate files. No /dev/fd or /dev/std{in,out,err} or /proc/pid.

Something like the following (which isn't working, so somewhere my concepts, and thus likely some of the comment annotations, are muddled):

child()
{
  sed '1s|^|child: |;q'   # prepend 'child: ' to first input line and quit
}

exec 4>&1           # open file descriptor 4 duplicated as stdout

# give the shell some time to start the child, then send data to child via fd 4
{ sleep 2; echo foo >&4; } &

out=$(child 4<&0)   # connect fd 4 to stdin in child process

echo "out: $out"

I was hoping to see 'child: foo' in out. But instead I see foo on stdout and child() never terminates (so clearly the data is not going to the input file descriptor of the child).

Update: Adding a use case, per request.

In a loop, send data to a utility that reads stdin without having to re-spawn said utility each time through the loop. Having to re-fork/exec the utility every time through the loop is expensive. So... run utility as a background child process (exec just once) and send data from parent via the input file descriptor available to the child.

Update 2:

I guess I'm really trying to do what mkfifo does (create a in/out pair of fds where the output fd in the parent is connected to the input fd of the child, and the out fd of the child to the in fd of the parent), but without mkfifo being available (and if possible without temporary pipe files - i.e., just using anonymous file descriptors).

Juan
  • 834
  • 10
  • 17
  • 1
    You can't do that without fifos or temporary files. There are workarounds in some shells, but they're all using extensions. (Notice that this has nothing to do with the child running in the fg/bg, but with the shell not having any way to create anonymous pipes other that via the cmd | cmd syntax). FWIW, exec 1>&4 will not work unless fd 4 is already opened, in which case it will make fd 1 (stdout) an alias of it (dup2(4, 1)). –  Nov 16 '19 at 18:30
  • Can you add to your question what (not how) you are trying to do. – ctrl-alt-delor Nov 16 '19 at 18:36
  • @ctrl-alt-delor: I added a use case, which may or may not help clarify. Specifically in the simplified example, I want to send data via a numbered file descriptor to a child process. So child should be waiting on a read of fd 4 and I want to pass data to fd 4 in the parent (and have the child read and act on that data). – Juan Nov 16 '19 at 18:52
  • Sorry I don't get it. In the comment, you say there are two things that you are trying to do A and B. However I can't see the difference. Then in the question, I see nothing that an additional file descriptor will help with. Can you tell us more, put everything in question. Then use comment to tell me that you are done. – ctrl-alt-delor Nov 16 '19 at 18:59
  • @ctrl-alt-delor Sorry it's not clear. I am trying to pass data to an input file descriptor of a background child process that was forked earlier in a shell script. In the example, how can I fix it to get out to have the value 'child: foo' after the parent passes 'foo' to the child via a file descriptor? – Juan Nov 16 '19 at 19:05
  • @ctrl-alt-delor Continuing the previous comment - I'm not sure at the moment how to edit the Q to make that more clear to all. Obviously the example doesn't work so I can understand why it's hard to grok the intent, but I am trying to pass data later in the script via a numbered fd to a previously forked child background process. – Juan Nov 16 '19 at 19:13
  • Doesn't seem possible without named pipes. As far as I'm concerned there is no way to read from a descriptor opened for writing; I mean shell does that using builtin pipes, like cmd | cmd, the alternative to this is named pipes, and that's all –  Nov 16 '19 at 19:18
  • You might want to elaborate on your use case btw –  Nov 16 '19 at 19:23
  • @oguzismail - I definitely want to read in the child from an fd opened for input. So my example construction is flawed. I just can't figure out the syntax to "do what I want" (read from an numbered input fd in bg child, and write, some time later, to an fd from the parent that is available to the child). I think I do need to associate in/out in child/parent and cmd|cmd is the classic non-named piped way. But my input to the child is generated later in the script (scattered around in the real example not shown). Maybe it can't be done, as you say. – Juan Nov 16 '19 at 19:27
  • I think I do need to associate in/out in child/parent and cmd|cmd is the classic non-named piped way exactly, and it's not possible in this case; you can not connect the current execution environment's stdout to another process' stdin from within the current execution environment itself, this must be done from the outside; and that's not what you want to do. This is probably why they created named pipes –  Nov 16 '19 at 19:34
  • @ctrl-alt-delor - I added Update 2. Maybe that clarifies it better. I think I'm wanting to create a pair of in/out fds in the parent and then swap them to out/in in the child... using numbered fd redirection. – Juan Nov 16 '19 at 19:41
  • 1
    For the use case from your update: while :; do echo yup; done | your_utility. (yes, that does work; it may be that your_utility is using buffered i/o). As to your "mkfifo or tempfiles without mkfifo or tempfiles", you're free to think I'm talking out of my ass; but if you really have a problem, better explain what you're trying to achieve exactly, maybe there are better ways to do it than the one you have latched onto. –  Nov 16 '19 at 20:24

1 Answers1

0

(not an answer, a long comment) Some similar questions:

glenn jackman
  • 85,964
  • Thanks. I've already searched quite a bit. I did not find any hits. The links you provided do not answer the question. Most of them point to mkfifo which is not available on some embedded systems I am targeting (and it can be weaker security-wise than file descriptor redirection since it creates a file on the filesystem that can be more easily accessed by unauthorized processes). – Juan Nov 16 '19 at 18:58