Can someone provide a couple of examples on how to use coproc?
|
|
|
co-processes are a However, the behaviour and interface is significantly different between the 3 shells. The idea is the same, though: it allows to start a job in background and being able to send it input and read its output without having to resort to named pipes. That is done with unnamed pipes with most shells and socketpairs with recent versions of ksh93 on some systems. In ksh co-processesIn
You feed data to
or
And read
or
To close the writing end of the pipe
And to close the reading end of the other pipe (the one
You cannot start a second co-process unless you first save the pipe file descriptors to some other fds. For instance:
zsh co-processesIn
Doing:
Note: This doesn't move the For instance, to close the feeding end:
In addition to pipe based co-processes, Here are some examples. Start the co-process
(Here, Feed a co-process data:
Read co-process data (in the simplest case):
Like bash co-processesThe bash syntax is a lot newer, and builds on top of a new feature recently added to ksh93, bash, and zsh. It provides a syntax to allow handling of dynamically-allocated file descriptors above 10.
Basic syntaxThe basic syntax for starting a co-process looks like
In But in Feed data to the co-process:
Read data from the co-process:
With the basic syntax, you can start only one co-process at the time. Extended syntaxIn the extended syntax, you can name your co-processes (like in
The command has to be a compound command. (Notice how the example above is reminiscent of This time, the file descriptors are in You can start more than one co-process at a time—but you do get a warning when you start a co-process while one is still running (even in non-interactive mode). You can close the file descriptors when using the extended syntax.
Note that closing that way doesn't work in bash versions prior to 4.3 where you have to write it instead:
As in But in yash process and pipeline redirection
You'd start a co-process with:
Which first creates a Note that the close-on-exec flag is not set on those file descriptors. To feed data:
To read data:
And you can close fds as usual:
Now, why they are not so popularhardly any benefit over using named pipesCo-processes can easily be implemented with standard named pipes. I don't know when exactly named pipes were introduced but it's possible it was after
Can be written with:
Interacting with those is more straightforward—especially if you need to run more than one co-process. (See examples below.) The only benefit of using deadlock-proneShells use pipes in a few constructs:
In those, the data flows in only one direction between different processes. With co-processes and named pipes, though, it's easy to run into deadlock. You have to keep track of which command has which file descriptor open, to prevent one staying open and holding a process alive. Deadlocks can be tricky to investigate, because they may occur non-deterministically; for instance, only when as much data as to fill one pipe up is sent. works worse than
|
|
|
Great answer indeed. I don't know when specifically it was fixed, but as of at least
bash 4.3.11, you can now close coproc file descriptors directly, without the need for an aux. variable; in terms of the example in your answer exec {tr[1]}<&- would now work (to close the coproc's stdin; note that your code (indirectly) tries to close {tr[1]} using >&-, but {tr[1]} is the coproc's stdin, and must be closed with <&-). The fix must have come somewhere between 4.2.25, which still exhibits the problem, and 4.3.11, which doesn't.
– mklement0
Apr 14 '15 at 21:03
|
||
|
@mklement0, thanks.
exec {tr[1]}>&- does indeed seem to work with newer versions and is referenced in a CWRU/changelog entry (allow words like {array[ind]} to be valid redirection... 2012-09-01). exec {tr[1]}<&- (or the more correct >&- equivalent though that makes no difference as that just calls close() for both) doesn't close the coproc's stdin, but the writing end of the pipe to that coproc.
– Stéphane Chazelas
Jun 7 '15 at 20:26
|
||
|
|
Thanks for researching, clarifying, and thanks for updating your answer. Can I suggest that you mention the 4.3 thing not only in the code comment, but also in the text above, such as "a bit cumbersome in Bash versions before 4.3"?
– mklement0
Jun 8 '15 at 2:39
|
||
|
|||
|
About deadlocks: the
stdbuf command can help to prevent at least some of them. I used it under Linux and bash. Anyway I believe @StéphaneChazelas is right in the Conclusion: the "head scratching" phase ended for me only when I switched back to named pipes.
– Matteo Tenca
May 24 at 1:33
|
|
Co-processes were first introduced in a shell scripting language in 1988 with ksh. The syntax to launch a co-process under ksh is More than a couple of decades later, bash which was lacking this feature finally introduced it in its 4.0 release. Unfortunately, an incompatible and more complex syntax was selected. Under bash 4.0 and newer, you can launch a co-process with the
You can then pass something to the command stdin that way:
and read awk output with:
Under ksh, that would have been:
|
|||||||||
|
|
What is a "coproc"? It's short for "co-process" which means a second process cooperating with the shell. It's very similar to a background job started with an "&" at the end of the command, except that instead of sharing the same standard input and output as its parent shell, its standard I/O is connected to the parent shell by a special kind of pipe called a FIFO.For reference click here One starts a coproc in zsh with
The command has to be prepared to read from stdin and/or write to stdout, or it isn't of much use as a coproc. Read this article here it provides a case study between exec and coproc |
|||||||||||||||||||||
|
|
Here is another good (and working) example -- a simple server written in BASH. Please note that you would need OpenBSD's server.sh:
client.sh:
Usage:
|
|||
|
|